home *** CD-ROM | disk | FTP | other *** search
/ Enter 2004 January / enter-2004-01.iso / files / maxima-5.9.0.exe / {app} / libexec / maxima / 5.9.0 / omplotdata < prev   
Encoding:
Text File  |  2003-02-09  |  155.8 KB  |  5,297 lines

  1. #!/bin/sh
  2. # comment \
  3. exec wish "$0" "$@"
  4. #############################################
  5. ##### Copyright William Schelter 1997 #######
  6. #############################################
  7. set ws_openMath(date) 12/09/2000
  8.  
  9. ###### plotting.tcl ######
  10. ############################################################
  11. # Netmath       Copyright (C) 1998 William F. Schelter     #
  12. # For distribution under GNU public License.  See COPYING. # 
  13. ############################################################
  14. ## source plotconf.tcl
  15.  
  16. ###### plotconf.tcl ######
  17. ############################################################
  18. # Netmath       Copyright (C) 1998 William F. Schelter     #
  19. # For distribution under GNU public License.  See COPYING. # 
  20. ############################################################
  21.  
  22. ## source private.tcl
  23.  
  24. ###### private.tcl ######
  25. ############################################################
  26. # Netmath       Copyright (C) 1998 William F. Schelter     #
  27. # For distribution under GNU public License.  See COPYING. # 
  28. ############################################################
  29.  
  30. # a private way of storing variables on a window by window
  31. # basis
  32.  
  33. proc makeLocal { win args } {
  34.   foreach v $args {
  35.      uplevel 1 set  $v \[oget $win $v\]
  36.  }
  37. }
  38.  
  39. proc linkLocal { win args } {
  40.   foreach v $args {
  41.       uplevel 1 upvar #0 _WinInfo${win}\($v) $v
  42.  }
  43. }
  44.  
  45. proc clearLocal { win } {
  46.     global _WinInfo$win
  47.        # puts "clearing info for $win in [info level 1]"
  48.  
  49.     catch { unset _WinInfo$win }
  50. }
  51.  
  52.  
  53. proc oset { win var val } {
  54.   global _WinInfo$win
  55.   set _WinInfo[set win]($var) $val
  56. }
  57.  
  58. proc oarraySet { win vals } {
  59.   global _WinInfo$win
  60.   array set  _WinInfo$win $vals
  61. }
  62.  
  63. proc oloc { win var } {
  64.   return _WinInfo[set win]($var)
  65. }
  66.  
  67. proc oarray { win  } {
  68.   return _WinInfo[set win]
  69. }
  70.  
  71. proc oget { win var } {
  72.   global _WinInfo$win
  73.   return [set _WinInfo[set win]($var)]
  74. }
  75.  
  76.  
  77. ## endsource private.tcl
  78. ## source parse.tcl
  79.  
  80. ###### parse.tcl ######
  81. ############################################################
  82. # Netmath       Copyright (C) 1998 William F. Schelter     #
  83. # For distribution under GNU public License.  See COPYING. # 
  84. ############################################################
  85.  
  86. ## source getopt.tcl
  87.  
  88. ###### getopt.tcl ######
  89. ############################################################
  90. # Netmath       Copyright (C) 1998 William F. Schelter     #
  91. # For distribution under GNU public License.  See COPYING. # 
  92. ############################################################
  93. ## source macros.tcl
  94.  
  95. ###### macros.tcl ######
  96. ############################################################
  97. # Netmath       Copyright (C) 1998 William F. Schelter     #
  98. # For distribution under GNU public License.  See COPYING. # 
  99. ############################################################
  100. proc desetq {lis lis2} {
  101.     set i 0
  102.     foreach v $lis {
  103.     uplevel 1 set $v [list [lindex $lis2 $i]]
  104.     set i [expr {$i + 1}]
  105.     }
  106. }
  107.  
  108. proc assoc { key lis args } {
  109.     foreach { k val } $lis {
  110.     if { "$k" == "$key" } {
  111.         return $val }
  112.     }
  113.     return [lindex $args 0]
  114. }
  115.  
  116. proc delassoc { key lis } {
  117.     foreach { k val } $lis {
  118.     if { "$k" != "$key" } {
  119.     lappend new $k $val
  120.     }
  121.     }
  122.     return $new
  123. }
  124.  
  125.  
  126. proc putassoc {key lis value } {
  127.     set done 0
  128.     foreach { k val } $lis {
  129.     if { "$k" == "$key" } {
  130.         set done 1
  131.         set val $value
  132.     }
  133.     lappend new $k $val
  134.     }
  135.     if { !$done } {
  136.     lappend new $key $value
  137.     }
  138.     return $new
  139. }
  140.  
  141. proc intersect { lis1 lis2 } {
  142.     set new ""
  143.     foreach v $lis1 { set there($v) 1 }
  144.     foreach v $lis2 { if { [info exists there($v)] } { lappend new $v }}
  145.     return $new
  146. }
  147.  
  148.  
  149.  
  150. #
  151.  #-----------------------------------------------------------------
  152.  #
  153.  # ldelete --  remove all copies of ITEM from LIST
  154.  #
  155.  #  Results: new list without item
  156.  #
  157.  #  Side Effects: 
  158.  #
  159.  #----------------------------------------------------------------
  160. #
  161. proc ldelete { item list } {
  162.     while { [set ind [lsearch $list $item]] >= 0  } {
  163.     set list [concat [lrange $list 0 [expr {$ind -1}]] [lrange $list [expr {$ind +1}] end]]
  164.     }
  165.     return $list
  166. }
  167.  
  168. # apply f a1 a2 a3 [list  u1 u2 ..un]   , should call
  169. # f with n+3 arguments.
  170. proc apply {f args } {
  171.     set lis1 [lrange $args 0 [expr {[llength $args] -2}]]
  172.     foreach v [lindex $args end] { lappend lis1 $v}
  173.     set lis1 [linsert $lis1  0 $f]
  174.     uplevel 1 $lis1
  175. }
  176.  
  177.  
  178.  
  179.  
  180.  
  181.  
  182. ## endsource macros.tcl
  183.  
  184. #####sample option list.   Error will be signalled if "Required" option
  185. ##### not given.
  186. #set dfplotOptions {
  187. #    {xdot Required {specifies dx/dt = xdot.  eg -xdot "x+y+sin(x)^2"} }
  188. #    {ydot Required {specifies dy/dt = ydot.  eg -ydot "x-y^2+exp(x)"} }
  189. #    {xradius 10 "Width in x direction of the x values" }
  190. #    {yradius 10 "Height in y direction of the y values"}
  191. #}
  192.  
  193.  
  194. #
  195.  #-----------------------------------------------------------------
  196.  #
  197.  # optLoc --  if $usearray is not 0, then the OPTION is stored 
  198.  # in a hashtable, otherwise in the variable whose name is the
  199.  # same as OPTION.  
  200.  #  Results: a form which when 'set' will allow storing value.
  201.  #
  202.  #  Side Effects: none
  203.  #
  204.  #----------------------------------------------------------------
  205. #
  206. proc optLoc { op ar }  {
  207.   #  puts "$ar,[lindex $op 0]"
  208.   # puts "return=$ar\([lindex $op 0]\)"
  209.    if { "$ar" == 0 } {
  210.        return [lindex $op 0]
  211.    } else {
  212.      #puts "$ar\([lindex $op 0]\)"
  213.     return "$ar\([lindex $op 0]\)" }
  214.  
  215. }
  216.  
  217.  
  218. #
  219.  #-----------------------------------------------------------------
  220.  #
  221.  # getOptions --  given OPTLIST a specification for the options taken,
  222.  # parse the alternating keyword1 value1 keyword2 value2 options_supplied
  223.  # to make sure they are allowed, and not just typos, and to supply defaults
  224.  # for ones not given.   Give an error message listing options.
  225.  # a specification is  { varname default_value "doc string" }
  226.  # and optlist, is a list of these.   the key should be -varname
  227.  # 
  228.  #  -debug 1 "means print the values on standard out"
  229.  #  -allowOtherKeys 1 "dont signal an error if -option is supplied but not in
  230.  #                     the list"
  231.  #  -usearray "should give a NAME, so that options are stored in NAME(OPTION)
  232.  #  -setdefaults "if not 0 (default is 1) do `set OPTION dflt' for all options"
  233.  # If a key is specified twice eg.  -key1 val1 -key1 val2, then the first
  234.  # value val1 will be used 
  235.  #  Results:
  236.  #
  237.  #  Side Effects: set the values in the callers environment
  238.  #
  239.  #----------------------------------------------------------------
  240. #
  241.  
  242. proc getOptions { optlist options_supplied args } {
  243.    # global  getOptionSpecs
  244.  
  245.     set ar [assoc -usearray $args 0]
  246.     set help [assoc -help $args ""]
  247.     if { "$ar" != "0" } { global $ar }
  248.     set debug [assoc -debug $args 0]
  249.     set allowOtherKeys [assoc -allowOtherKeys $args 0]
  250.     set setdefaults [assoc -setdefaults $args 1]
  251.     set supplied ""
  252.  
  253.     foreach {key val } $options_supplied {
  254.     if { [info exists already($key)] } { continue }
  255.     set already($key) 1
  256.     set found 0
  257.     foreach op $optlist {
  258.         if { "$key" == "-[lindex $op 0]" } {
  259.         uplevel 1 set [optLoc $op $ar] [list $val]
  260.         
  261.         append supplied " [lindex $op 0]"
  262.         set found 1
  263.         break
  264.         }
  265.     }
  266.     set caller global
  267.  
  268.     if { $found == 0  && !$allowOtherKeys } {
  269.         catch {set caller [lindex [info level -1] 0]}
  270.              error "`$caller' does not take the key `$key':\n[optionHelpMessage $optlist]\n$help"
  271.  
  272.         }
  273.     }
  274.     foreach op $optlist {
  275.      if { [lsearch $supplied [lindex $op 0]] < 0 } {
  276.            if { "[lindex $op 1]" == "Required" } {
  277.            catch {set caller [lindex [info level -1] 0]}           
  278.               error "`-[lindex $op 0]' is required option for `$caller':\n[optionHelpMessage $optlist]"
  279.             }
  280.               if { $setdefaults }  {
  281.             
  282.         uplevel 1 set [optLoc $op $ar] [list [lindex $op 1]]
  283.           }
  284.     }
  285.     # for debugging see them.
  286.     # if { $debug } {   uplevel 1 puts "[optLoc $op $ar]=\$[optLoc $op $ar]"}
  287.      if { $debug } {   puts "[optLoc $op $ar]=[safeValue [optLoc $op $ar] 2]"}
  288.     
  289.     }
  290. }
  291.  
  292. proc getOptionDefault { key optionList } {
  293.  foreach v $optionList {
  294.   if { "[lindex $v 0]" == "$key" } { return [lindex $v 1]}
  295.    }
  296.  return ""
  297. }
  298.  
  299. proc assq {key list {dflt ""}} {
  300.     foreach v $list { if { "[lindex $v 0]" == "$key" } { return $v }}
  301.     return $dflt
  302. }
  303.  
  304. proc safeValue { loc level} {
  305.   if { ![catch { set me [uplevel $level set $loc] } ] } {
  306.      return $me  }  else {return "`unset'" }
  307. }
  308.      
  309.   
  310.  
  311. proc optionFirstItems { lis } {
  312.     set ans ""
  313.     foreach v $lis { append ans " [list [lindex $v 0]]" }
  314.     return $ans
  315. }
  316.  
  317. proc optionHelpMessage { optlist } {
  318.     set msg ""
  319.     foreach op $optlist  {    
  320.     append msg \
  321.         " -[lindex $op 0] \[ [lindex $op 1] \] --[lindex $op 2]\n"
  322.         }
  323.     return $msg
  324.     }
  325.  
  326.  
  327. #
  328.  #-----------------------------------------------------------------
  329.  #
  330.  # setSplittingOptionsRest --  takes ARGLIST and splits it into
  331.  # two lists, the first part it stores in KEYPAIRS and the second in REST
  332.  # 
  333.  #
  334.  #  Results: none
  335.  #  
  336.  #
  337.  #  Side Effects: sets the variables in the local frame passed to KEYPAIRS 
  338.  #
  339.  #----------------------------------------------------------------
  340. #    
  341. proc setSplittingOptionsRest {  keypairs rest arglist } {
  342.     upvar 1 $keypairs keys
  343.     upvar 1 $rest res
  344.     set i 0
  345.     while { 1 } {
  346.     if { $i >= [llength $arglist] } { break } 
  347.     if { "[string range [lindex $arglist $i] 0 0]" == "-" } {
  348.         incr i 2
  349.     } else { break }
  350.     }
  351.     set keys [lrange $arglist 0 [expr $i -1]]
  352.     set res [lrange $arglist  $i end]
  353. }
  354.     
  355.     
  356.     
  357.     
  358.  
  359.  
  360. ## endsource getopt.tcl
  361.  
  362. catch { unset Parser }
  363.  
  364. foreach v  { { ( 120 } { \[ 120 } { ) 120 } { \] 120 }  { ^ 110}
  365.          {* 100} { / 100} {% 100}  {- 90 } { + 90 }
  366.            { << 80} { >> 80 } { < 70 } { > 70 } { <= 70 } {>= 70}
  367.        { == 60 } { & 50} { | 40 } { , 40 } {= 40}
  368.        { && 30 } { || 20 } { ? 10 } { : 10 }  { ; 5 }}  {
  369.            set parse_table([lindex $v 0]) [lindex $v 1]
  370.            set getOp([lindex $v 0]) doBinary
  371.            
  372.        }
  373.  
  374. proc binding_power {s} {
  375.     global parse_table billy
  376.     set billy $s
  377.     if { [catch { set tem $parse_table($s) }] } { return 0 } else { return $tem }
  378. }
  379.  
  380. proc getOneMatch { s inds } {
  381.     return [string range $s [lindex $inds 0] [lindex $inds 1]]
  382. }
  383. proc parseTokenize { str } {
  384.     regsub  -all {[*][*]} $str "^" str
  385.     set ans ""
  386.     while { [string length $str ] > 0 } {
  387. #    puts "ans=$ans,str=$str"    
  388.     set str [string trimleft $str " \t\n" ]
  389.     set s [string range $str 0 1]
  390.     set bp [binding_power $s]
  391.     if { $bp > 0 } { append ans " $s"
  392.        set str [string range $str 2 end]
  393.     continue
  394.     } else {
  395.     set s [string range $s 0 0]
  396.         set bp [binding_power $s]
  397.         if { $bp > 0 } { append ans " $s"
  398.        set str [string range $str 1 end]
  399.     continue
  400.    }
  401.   }
  402.   if { "$s" == "" } {
  403.       return $ans
  404.   }
  405.   if { [regexp -indices {^[0-9.]+([eE][+---]?[0-9]+)?} $str all] } {
  406.       append ans " { number [getOneMatch $str $all] }"
  407.      # append ans " [getOneMatch $str $all]"
  408.       set str [string range $str [expr {1+ [lindex $all 1]}] end]
  409.   }  elseif { [regexp -indices {^[$a-zA-Z][a-zA-Z0-9]*} $str all] } {
  410.        append ans " { id [getOneMatch $str $all] } "
  411.       # append ans " [getOneMatch $str $all]"
  412.       set str [string range $str [expr {1+ [lindex $all 1]}] end]
  413.   }  else { error "parser unrecognized: $str"
  414.   }
  415.   }
  416.   return $ans
  417. }
  418.  
  419. set Parser(reserved) " acos cos hypo sinh asin cosh log sqrt atan exp log10 tan atan2 floor pow tanh ceil fmod sin abs double int round"
  420.  
  421. set Parser(help) [join [list {
  422. The syntax is like C except that it is permitted to write x^n
  423. instead of pow(x,n).
  424. } "\nFunctions: $Parser(reserved)\n\nOperators: == % & || ( << <= ) : * >=  + && , | < >> - > ^ ? /" ] ""]
  425.  
  426.     
  427.  
  428. proc nexttok { } {
  429.     global Parser
  430.     set x [lindex $Parser(tokenlist) [incr Parser(tokenind) ]]
  431.     # puts "nexttok=$x"
  432.     if {[llength $x ] > 1 } {
  433.     set Parser(tokenval) [lindex $x 1]
  434.     return [lindex $x 0]
  435.     } else { return $x }
  436. }
  437.  
  438.  
  439. #
  440.  #-----------------------------------------------------------------
  441.  #
  442.  # parseToSuffixLists -- Convert EXPR1; EXPR2; ..
  443.  # to a list of suffix lists.  Each suffix list is suitable for
  444.  # evaluating on a stack machine (like postscript) or for converting
  445.  # further into another form.  see parseFromSuffixList.
  446.  #  "1+2-3^4;" ==>
  447.  #   {number 1} {number 2} + {number 3} {number 4} ^ -
  448.  #  Results: suffix list form of the original EXPR
  449.  #
  450.  #  Side Effects: none
  451.  #
  452.  #----------------------------------------------------------------
  453. #
  454. proc parseToSuffixLists { a }  {
  455.     global    Parser 
  456.     set Parser(result) ""
  457.     set Parser(tokenlist) [parseTokenize $a]
  458.     set Parser(tokenind) -1
  459.     set Parser(lookahead)  [nexttok]
  460.     #puts tokenlist=$Parser(tokenlist)
  461.     set ans ""
  462.     while { "$Parser(lookahead)" != ""  } {
  463.       getExpr  ; parseMatch ";"
  464.       #puts "here: $Parser(result) "    
  465.       append ans "[list    $Parser(result)] "
  466.       set Parser(result) ""     
  467.     }
  468.     return $ans
  469. }
  470.  
  471. proc parseMatch { t } {
  472.     global Parser
  473.     if { "$t" == "$Parser(lookahead)" } {
  474.     set Parser(lookahead)  [nexttok]
  475.     } else { error "syntax error: wanted $t"}
  476. }
  477.  
  478. proc emit { s args } {
  479.     global Parser
  480.     if { "$args" == "" }   {
  481.     append Parser(result) " $s"
  482.     # puts " $s "
  483.     } else {
  484.     append Parser(result) " {[lindex $args 0 ] $s}"
  485.     #puts " {[lindex $args 0 ] $s} "
  486.     }
  487. }
  488.  
  489. proc getExpr { } { getExprn 0 }
  490.  
  491. proc getExprn { n } {
  492.     global Parser
  493.     #puts "getExpr $n, $Parser(tokenind),$Parser(tokenlist)"
  494.     if { $n == 110 } {
  495.       getExpr120
  496.       return
  497.      }
  498.  
  499.     incr n 10
  500.     if  { $n == 110 } {
  501.        if { "$Parser(lookahead)" == "-" || "$Parser(lookahead)" == "+"  } {
  502.             if { "$Parser(lookahead)" == "-" } { set this PRE_MINUS } else {
  503.                set this PRE_PLUS }
  504.         parseMatch $Parser(lookahead)
  505.             getExprn $n
  506.         #puts "l=$Parser(lookahead),pl=$Parser(result)"
  507.             emit $this
  508.             return
  509.            } 
  510.            
  511.     }
  512.  
  513.     getExprn $n
  514.     while { 1 } {
  515.     if { [binding_power $Parser(lookahead)] == $n } {
  516.         set this $Parser(lookahead)
  517.         parseMatch $Parser(lookahead)
  518.             getExprn $n
  519.         if { $n == 110 } {
  520.         set toemit ""
  521.         while { "$this" == "^" &&  "$Parser(lookahead)" == "^" } {
  522.             # puts "p=$Parser(result),$
  523.             set this $Parser(lookahead)
  524.             append toemit " $this"
  525.             parseMatch $Parser(lookahead)
  526.             getExprn $n
  527.         }
  528.         foreach v $toemit { emit $v }
  529.         }
  530.         emit $this
  531.            
  532.     } else { return }
  533.     }
  534. }
  535.  
  536. proc getExpr120 { } {
  537.     global Parser
  538.     #puts "getExpr120, $Parser(tokenind),[lrange $Parser(tokenlist) $Parser(tokenind) end]"
  539.     while { 1 } {
  540.     if { "$Parser(lookahead)" == "(" } {
  541.         parseMatch $Parser(lookahead)
  542.         getExpr
  543.         parseMatch ")"
  544.         break;
  545.     } elseif { $Parser(lookahead) == "id" } {
  546.         emit $Parser(tokenval) id
  547.  
  548.         parseMatch $Parser(lookahead)
  549.         if { "$Parser(lookahead)" == "(" } {
  550.         getExpr120
  551.         emit funcall
  552.         }
  553.         break;
  554.     } elseif { $Parser(lookahead) == "number" } {
  555.         emit $Parser(tokenval) number
  556.         parseMatch $Parser(lookahead)
  557.         break;
  558.     } else { error "syntax error" }
  559.     }
  560. }
  561.  
  562. set getOp(PRE_PLUS) doPrefix
  563. set getOp(PRE_MINUS) doPrefix
  564. set getOp(funcall) doFuncall
  565. set getOp(^) doPower
  566. set getOp(:) doConditional
  567. set getOp(?) doConditional
  568.  
  569. proc doBinary { } {
  570.     uplevel 1 {set s $nargs; incr nargs -1 ;
  571.     if { "$x" == "," } {    set a($nargs) "$a($nargs) $x $a($s)"} else { 
  572.  
  573.     set a($nargs) "($a($nargs) $x $a($s))"} }
  574. }
  575.  
  576. proc doPower { } {
  577.     uplevel 1 {set s $nargs; incr nargs -1 ; set a($nargs) "pow($a($nargs),$a($s))" }
  578. }
  579. proc doFuncall {} {
  580.     uplevel 1 {
  581.     #puts nargs=$nargs
  582.     set s $nargs; incr nargs -1 ; set a($nargs) "$a($nargs)($a($s))"}
  583. }
  584.  
  585. proc doPrefix {} {
  586.   uplevel 1  { if { "$x" == "PRE_MINUS" } { set a($nargs) "-$a($nargs)" } }
  587. }
  588.  
  589. proc doConditional { } {
  590.     set x [uplevel 1 set x]
  591.     if { "$x" == "?" } { return }
  592.     # must be :
  593.     uplevel 1 { 
  594.     set s $nargs ; incr nargs -2 ;
  595.     set a($nargs) "($a($nargs) ? $a([expr {$nargs + 1}]) : $a($s))"
  596.  }
  597. }
  598.  
  599.  
  600. #
  601.  #-----------------------------------------------------------------
  602.  #
  603.  # parseFromSuffixList --  takes a token list, and turns
  604.  # it into a suffix form.  eg: 1 + 2 - 3 ^ 4 --> 1 2 + 3 4 ^ -
  605.  #  Results:
  606.  #
  607.  #  Side Effects: 
  608.  #
  609.  #----------------------------------------------------------------
  610. #
  611. proc parseFromSuffixList { list } {
  612.     global getOp
  613.   set stack ""
  614.   set lim [llength $list]
  615.   set i 0
  616.   set nargs 0
  617.   while { $i < $lim } {
  618.     set x [lindex $list $i ]
  619.     set bp [binding_power $x]
  620.     incr i
  621.    # all binary
  622.     if { [llength $x] > 1 } {
  623.     
  624.     set a([incr nargs]) [lindex $x 1]
  625.  
  626.      } else {
  627.      $getOp($x) }
  628.    }
  629.  
  630.   return $a(1)
  631. }
  632.     
  633.  
  634. #
  635.  #-----------------------------------------------------------------
  636.  #
  637.  # parseConvert --  given an EXPRESSION, parse it and find out
  638.  # what are the variables, and convert a^b to pow(a,b).  If
  639.  # -variables "x y" is given, then x and y will be replaced by $x $y
  640.  #  doall 1 is giv 
  641.  #  Results:
  642.  #
  643.  #  Side Effects: 
  644.  #
  645.  #----------------------------------------------------------------
  646. #
  647. set Parser(convertOptions) {
  648.     { doall 0 "convert all variables x to \$x" }
  649.     { variables "" "list of variables to change from x to \$x" }
  650. }
  651. proc parseConvert { expr args } {
  652.     global   Parser 
  653.     getOptions $Parser(convertOptions) $args
  654.     if { "$expr" == "" } { return [list {} {}] }
  655.     set parselist [parseToSuffixLists "$expr;"]
  656.     #puts "parselist=$parselist"
  657.     catch { unset allvars }
  658.     set new ""
  659.     set answers ""
  660.     foreach lis $parselist {
  661.       
  662.      foreach v $lis {
  663.  
  664.     if { ("[lindex $v 0]" == "id")
  665.     && ([llength $v] == 2)
  666.     && ([lsearch  $Parser(reserved) [set w [lindex $v 1]]] < 0)
  667.     } {  
  668.     if { ($doall != 0)  || ([lsearch  $variables $w] >= 0) } {
  669.         append new " {id \$$w}"
  670.         set allvars(\$$w) 1
  671.     } else {
  672.         set allvars($w) 1
  673.         append new " {$v}"
  674.     }   }  else {
  675.     if { [llength $v] > 1 } { 
  676.         append new " {$v}" } else {
  677.         append new " $v" }
  678.         }
  679.     }
  680.     #puts "new=$new"
  681.     append answers "[list [parseFromSuffixList $new]] "
  682.     set new ""
  683.  }
  684.     return [list $answers [array names allvars]]
  685. }
  686.  
  687. proc test { s } {
  688.     set me [parseFromSuffixList [lindex [parseToSuffixLists "$s;"] 0]]
  689.     puts $me
  690.     return "[eval expr $s] [eval expr $me]"
  691. }
  692.  
  693.  
  694.  
  695.  
  696. # Local Variables:
  697. # mode: tcl
  698. # version-control: t
  699. # End:
  700.  
  701.  
  702. ## endsource parse.tcl
  703. ## source textinsert.tcl
  704.  
  705. ###### textinsert.tcl ######
  706. ############################################################
  707. # Netmath       Copyright (C) 1998 William F. Schelter     #
  708. # For distribution under GNU public License.  See COPYING. # 
  709. ############################################################
  710.  
  711. proc mkTextItem { c x y args  } {
  712.     set font [assoc -font $args {Helvetica 14}]
  713.     set tags [assoc -tags $args {}]
  714.     set item [$c create text $x $y -text " " -width 440 -anchor n -font $font -justify left]
  715.     append tags text
  716.     foreach v $tags { $c addtag $v withtag $item}
  717.     $c bind text <1> "textB1Press $c %x %y"
  718.     $c bind text <B1-Motion> "textB1Move $c %x %y"
  719.     $c bind text <Shift-1> "$c select adjust current @%x,%y"
  720.     $c bind text <Shift-B1-Motion> "textB1Move $c %x %y"
  721.     $c bind text <KeyPress> "textInsert $c %A"
  722.     $c bind text <Return> "textInsert $c \\n"
  723.     $c bind text <Control-h> "textBs $c"
  724.     $c bind text <BackSpace> "textBs $c"
  725.     $c bind text <Delete> "textDel $c"
  726.     $c bind text <2> "textPaste $c @%x,%y" 
  727. }
  728.  
  729.  
  730. ## endsource textinsert.tcl
  731. ## source printops.tcl
  732.  
  733. ###### printops.tcl ######
  734. ############################################################
  735. # Netmath       Copyright (C) 1998 William F. Schelter     #
  736. # For distribution under GNU public License.  See COPYING. # 
  737. ############################################################
  738.  
  739. ### fix a4 size !
  740. set paperSizes {{letter 8.5 11} { A4 8.5 11} {legal 8.5 13}} 
  741.  
  742. set printOptions { 
  743.     { landscape  1 "Non zero means use landscape mode in printing" }
  744.     { tofile 1 "Non zero means print to file" }
  745.     { pagewidth "" "Figure width" }
  746.     { pageheight "" "Figure height" }
  747.     { papersize letter "letter, legal or A4"}
  748.     { hoffset .5 "Left margin for printing"}
  749.     { voffset .5 "Right margin for printing"}
  750.     { xticks 20 "Rough number of ticks on x axis"}
  751.     { yticks 20 "Rough number of ticks on y axis"}
  752.     { domargin 1 "Print the frame and the margin ticks"}
  753.     { printer "" "Printer to print to, eg lw8b " }
  754.     { title "" "Title" }
  755.     { psfilename "~/sdfplot.ps" "Postscript filename" }
  756.     { gsview "gsview32" "postscript viewer, used for printing under Windows" }
  757.     { centeronpage 1 ""} 
  758. }
  759.  
  760. # proc getPageOffsets { widthbyheight} {
  761. #     global printOption paperSizes
  762. #     puts "wbh=$widthbyheight"
  763. #     set pwid 8.5
  764. #     set phei 11.0
  765.  
  766. #     foreach v $paperSizes {
  767. #     if { "[lindex $v 0]" == "$printOption(papersize)" } {
  768. #         set pwid [lindex $v 1]
  769. #         set phei [lindex $v 2]
  770. #     }
  771. #     }
  772. #     set wid [expr {$pwid - 2* $printOption(hoffset)}]
  773. #     set hei [expr {$phei - 2* $printOption(voffset)}]
  774. # #    if { $printOption(landscape) } {set widthbyheight [expr  {1.0 /$widthbyheight}]}
  775. # #    set w $wid ; set hei $wid ; set wid $w
  776.  
  777. #     puts "pw=$wid,ph=$hei,w/h=$widthbyheight,hh=[expr {$hei * $widthbyheight}], ww=[expr {$wid / $widthbyheight}]"
  778.  
  779. #     set fac   $widthbyheight
  780. #     puts "fac=$fac"
  781. #     if { $fac * $hei < $wid } {
  782.     #     set iwid [expr {$fac *$hei}]
  783. #     set ihei $hei
  784.  
  785. #     } else {
  786.     #     set ihei [expr {$wid / $fac}]
  787.  
  788. #     set iwid $wid
  789.  
  790. #     }
  791.  
  792. #     if { $printOption(landscape) } { set fac1 [expr {1/$fac}] }
  793. #     if { $wid/$hei > $fac } {
  794. #     set ihei $hei
  795.     #     set iwid   [expr {$hei / $fac }]
  796.  
  797. #     } else {
  798. #      set iwid $wid
  799.     #      set ihei [expr {$wid * $fac }]
  800. #     }
  801.  
  802. #     #-pagex = left margin (whether landscape or not)
  803. #     #-pagey = right margin (whether landscape or not)
  804. #     #-pagewidth becomes vertical height if landscape
  805. #     #-pageheight becomes horiz width if landscape
  806.     
  807. #     set xoff [expr {($pwid-$iwid)/2.0}]
  808. #     set yoff [expr  {($phei-$ihei)/2.0}]
  809.  
  810. #     if { $printOption(landscape) } {
  811. #     set h $ihei
  812. #     set ihei $iwid
  813. #     set iwid $h
  814. #     }
  815.  
  816. #     puts "phei=$phei,ihei=$ihei,yoff=$yoff,voff=$printOption(voffset)"
  817. #     set ans "-pagex [set xoff]i -pagey [set yoff]i \
  818. #         -pagewidth [set iwid]i -pageheight [set ihei]i"
  819. #     set ans "-pagex [set xoff]i -pagey [set yoff]i \
  820. #         -pagewidth [set iwid]i -pageheight [set ihei]i"    
  821. #     return $ans
  822. # }
  823.  
  824. proc swap { a b } {
  825.     set me [uplevel 1 set $b]
  826.     uplevel 1 set $b \[set $a\]
  827.     uplevel 1 set $a [list $me]
  828. }
  829.  
  830. proc getPageOffsets { widthbyheight} {
  831.     global printOption paperSizes
  832.     #puts "wbh=$widthbyheight"
  833.     set pwid 8.5
  834.     set phei 11.0
  835.  
  836.     foreach v $paperSizes {
  837.     if { "[lindex $v 0]" == "$printOption(papersize)" } {
  838.         set pwid [lindex $v 1]
  839.         set phei [lindex $v 2]
  840.     }
  841.     }
  842.     set wid [expr {$pwid - 2* $printOption(hoffset)}]
  843.     set hei [expr {$phei - 2* $printOption(voffset)}]
  844.     if { $printOption(landscape) } {
  845.     swap wid hei
  846. #    swap pwid phei
  847.     }
  848.     if { $wid / $hei  < $widthbyheight  } {
  849.     # width dominates
  850.     set iwid $wid
  851.     set ihei [expr {$wid / $widthbyheight }]
  852.     append opts " -pagewidth [set wid]i"
  853.     } else {
  854.     set ihei $hei
  855.     set iwid [expr {$hei * $widthbyheight }]
  856.     append opts " -pageheight [set hei]i"
  857.     }
  858.  
  859.     #-pagex = left margin (whether landscape or not)
  860.     #-pagey = right margin (whether landscape or not)
  861.     #-pagewidth becomes vertical height if landscape
  862.     #-pageheight becomes horiz width if landscape
  863.     
  864.     append opts " -pagex [expr {$pwid / 2.0}]i -pagey [expr {$phei / 2.0}]i "
  865.  
  866.     if { $printOption(landscape) } {
  867.         append opts " -rotate $printOption(landscape)" 
  868.     }
  869.     return $opts
  870. }
  871.  
  872. set printOption(setupDone) 0
  873.  
  874. proc getEnv { name } {
  875.   global env
  876.  if { [catch { set tem $env($name) } ] } { return "" }
  877.  return $tem
  878. }
  879. proc setPrintOptions { lis } {
  880.     global browser_version
  881.    global printOptions printOption printSetUpDone 
  882.     if { !$printOption(setupDone) } {
  883.     set printOption(setupDone) 1
  884.     getOptions $printOptions $lis -allowOtherKeys 1 \
  885.         -setdefaults [catch { source [getEnv HOME]/.printOptions }] -usearray printOption
  886.         if { "$printOption(printer)" == "" } {set printOption(printer) [getEnv PRINTER] } else { set printOption(printer) lw8b }
  887.     
  888.     }
  889.     if { [info exists browser_version] } { set printOption(tofile) 2 }
  890. }
  891.  
  892. proc mkentryPr { w var text buttonFont }  {
  893.      set fr $w ; frame $fr
  894.     uplevel 1 append topack [list " $fr"]
  895.     label $fr.lab -text "$text" -font $buttonFont
  896.     entry $fr.e -width 20 -textvariable $var -font $buttonFont
  897.     pack $fr.lab $fr.e -side left -expand 1 -padx 3 -fill x
  898. }
  899.  
  900.  
  901. proc mkPrintDialog { name args } {
  902.     global printSet argv env printOptions printOption printSetUpDone paperSizes buttonfont
  903.  
  904.     set canv [assoc -canvas $args ]
  905.     set buttonFont [assoc -buttonfont $args $buttonfont]
  906.     catch { destroy $name }
  907.     set dismiss "destroy $name"
  908.     if { "$canv" == "" } {
  909.      catch {destroy $name}
  910.     toplevel $name
  911.     wm geometry $name -0+20
  912.    
  913.     } else {
  914.         $canv delete printoptions
  915.         set name [winfo parent $canv].printoptions
  916.     # set name $canv.fr1
  917.         catch {destroy $name}
  918.     frame $name -borderwidth 2 -relief raised
  919.     
  920.     set item [$canv create window [$canv canvasx 10] [$canv canvasy  10] -window $name -anchor nw -tags printoptions]
  921.         $canv raise printoptions
  922.     set dismiss "$canv delete $item; destroy $name "
  923.     }
  924.     
  925.     frame $name.fr
  926.  
  927.     set w $name.fr
  928.     label $w.msg  -wraplength 600 -justify left -text "Printer Setup"
  929.     pack $w
  930.     pack $w.msg
  931.     set wb $w.buttons
  932.     frame $wb 
  933.     pack $wb -side left -fill x -pady 2m
  934.     set topack ""
  935.     catch { set printOption(psfilename) \
  936.         [file nativename $printOption(psfilename)]}
  937.     button $wb.ok -text "ok" -font $buttonFont  -command "destroy $name ; $canv delete printoptions"
  938.     radiobutton $wb.b0 -text "Save via ftp" -variable printOption(tofile) -relief flat -value 2 -command {set writefile "Save"} -font $buttonFont  -highlightthickness 0 
  939.     radiobutton $wb.b1 -text "Save as Postscript File" -variable printOption(tofile) -relief flat -value 1 -command {set writefile "Save"} -font $buttonFont  -highlightthickness 0 
  940.     radiobutton $wb.b2 -text "Print To Printer" -variable printOption(tofile) -relief flat -value 0 -command {set writefile "Print"} -font $buttonFont -highlightthickness 0 
  941.     checkbutton $wb.b3 -text "Center on Page" -variable printOption(centeronpage) -relief flat -font $buttonFont -highlightthickness 0 
  942.     checkbutton $wb.b4 -text "Landscape Mode" -variable printOption(landscape) -relief flat -font $buttonFont -highlightthickness 0 
  943.  
  944.     mkentryPr  $wb.pagewidth printOption(pagewidth) "Figure width" $buttonFont
  945.     mkentryPr  $wb.pageheight printOption(pageheight) "Figure height" $buttonFont
  946.     mkentryPr  $wb.hoffset printOption(hoffset) "Left margin for printing" $buttonFont
  947.     mkentryPr  $wb.voffset printOption(voffset) "bottom margin for printing" $buttonFont
  948.     mkentryPr  $wb.psfilename printOption(psfilename) "postscript filename" $buttonFont
  949.     mkentryPr  $wb.printer printOption(printer) "Printer to print to" $buttonFont
  950.     mkentryPr  $wb.gsview printOption(gsview) "postscript viewer, used for printing under Windows" $buttonFont
  951.    mkentryPr  $wb.xticks printOption(xticks) "Rough number of xticks" $buttonFont
  952.    mkentryPr  $wb.yticks printOption(yticks) "Rough number of yticks" $buttonFont
  953.     eval pack $wb.ok $wb.b0 $wb.b1 $wb.b2 $wb.b3 $wb.b4
  954.     eval pack $topack -expand 1
  955.  
  956.     foreach v  $paperSizes {
  957.     set papersize [lindex $v 0]
  958.         set lower [string tolower $papersize]
  959.         radiobutton $wb.$lower -text [lindex $v 0] -variable printOption(papersize) \
  960.        -value [lindex $v 0] -font $buttonFont -highlightthickness 0 
  961.     pack $wb.$lower -pady 2 -anchor w -fill x
  962.     }
  963.     checkbutton $wb.domargin -variable printOption(domargin) -text "do margin" 
  964.     pack $wb.domargin -pady 2 -anchor w -fill x
  965.  
  966.     frame $w.grid
  967.     pack $w.grid -expand yes -fill both -padx 1 -pady 1
  968.     grid rowconfig    $w.grid 0 -weight 1 -minsize 0
  969.     grid columnconfig $w.grid 0 -weight 1 -minsize 0
  970. }
  971.  
  972. proc markToPrint { win tag title } {
  973.     # puts "$win $tag"
  974.    # bind $win <1> "bindBeginDrag $win %x %y $tag [list $title]"
  975.     pushBind $win <1> "$win delete printrectangle ; popBind $win <1>"
  976.     pushBind $win <1> "bindBeginDrag $win %x %y $tag [list $title]; popBind $win <1>"    
  977. }
  978.  
  979. proc bindBeginDrag { win x y tag title } {
  980.     $win delete $tag printrectangle
  981.     set beginRect "[$win canvasx $x] [$win canvasy $y]"
  982.     set it1 [eval $win create rectangle $beginRect $beginRect -tags $tag -width 3]
  983.     set old [bind $win <B1-Motion>]
  984.     set new "eval $win coords $it1 \
  985.         $beginRect \[$win canvasx %x\] \[$win canvasy %y\]; \
  986.         "
  987.     if { "$old" == "$new" } {set old ""}
  988.     bind $win <B1-Motion> $new
  989.     bind $win <ButtonRelease-1> "bind $win <B1-Motion> [list $old];\
  990.         bind $win <ButtonRelease-1> {} ; unbindAdjustWidth $win $tag [list $title];"
  991. }
  992.  
  993. proc unbindAdjustWidth { canv tag title } {
  994.     set win [winfo parent $canv]
  995.     global printOption
  996.  
  997.     set it [$canv find withtag $tag]
  998.     set co1 [$canv coords $tag]
  999.     set co [$canv coords $it]
  1000.    # if { "$co" != "$co1" } {puts differ,$co1,$co}
  1001.     desetq "x1 y1 x2 y2" $co
  1002.     set center [expr { ($x1+$x2 )/2}]
  1003.    set h [expr {$y2 - $y1}]
  1004.     set it [$canv find withtag $tag]
  1005.    set new [$canv create rectangle $x1 $y1 $x2 $y2 -outline white -width [expr {$h* .04}] -tags [concat $tag bigger] ]
  1006.  
  1007.     # puts "<marginTicks $canv $x1 $y1 $x2 $y2 printrectangle>"
  1008.     marginTicks $canv [storx$win $x1] [story$win $y2] [storx$win $x2] [story$win $y1] "printrectangle marginticks"
  1009.     desetq "a1 b1 a2 b2" [$canv bbox $new]
  1010.    set textit [$canv create text $center [expr {$y1 - $h *.03}] \
  1011.         -font [font create -family Courier -size 14 -weight bold] -text "$title" \
  1012.         -anchor s -tags [concat $tag bigger title]]
  1013.  
  1014.     set bb [$canv bbox $textit]
  1015.    $canv create rectangle $a1 [lindex $bb 1]  $a2 [expr {$y1 - 0.02 * $h}]  -tags $tag -fill white -outline {}
  1016.    $canv itemconfig $it -width [expr {$h *.002}]
  1017.     $canv raise $it
  1018.     $canv raise $textit
  1019.     $canv raise marginticks
  1020.     if { $printOption(domargin) == 0 } {
  1021.     $canv delete marginticks
  1022.     }
  1023.  
  1024.     $canv create text [expr {($a1 + $a2)/2.0}] [expr {$y2 + .01*$h  }] -anchor nw -text "For [getEnv USER] [clock format [clock seconds]]" -font [font create -family Courier -size 10 -weight normal] -tag $tag
  1025.     # puts h=$h
  1026.  
  1027. }
  1028.     
  1029.  
  1030. proc getPSBbox  { } {
  1031.   set fi [open /home/wfs/sdfplot.ps r]
  1032.   set me [read $fi 500]
  1033.   regexp {BoundingBox: (-*[0-9]+) (-*[0-9]+) (-*[0-9]+) (-*[0-9]+)} $me junk x1 y1 x2 y2
  1034.     set w [expr {72 * 8.5}]
  1035.     set h [expr {72 * 11}]
  1036.     # puts "hei=[expr {$y2-$y1}],tm=[expr {$h - $y2}],bm=$y1"
  1037.     # puts "wid=[expr {$x2-$x1}],lm=$x1,rm=[expr {$w - $x2}]"
  1038.     # puts "hei=[expr {($y2-$y1)/72.0}],tm=[expr {($h - $y2)/72.0}],bm=([expr {$y1/72.0}])"
  1039.     #puts "wid=[expr {($x2-$x1)/72.0}],lm=([expr {$x1/72.0}]),rm=[expr {($w - $x2)/72.0}]"    
  1040.   close $fi
  1041. }
  1042.  
  1043.  
  1044. ## endsource printops.tcl
  1045. # set font {Courier 8}
  1046. set fontCourier8 "-*-Courier-Medium-R-Normal--*-120-*-*-*-*-*-*"
  1047.  
  1048. if { "[winfo screenvisual .]" == "staticgray" } { set axisGray black
  1049. }     else  { set axisGray gray60}
  1050.  
  1051. set writefile  "Save"
  1052. # make printing be by ftp'ing a file..
  1053.  
  1054. if {[catch { set doExit }] } { set doExit ""}
  1055. set width_ [winfo screenwidth .]
  1056. if { $width_ >= 1280 } { set fontSize 12
  1057.   } elseif { $width_ <= 640} { set fontSize 8 } else {
  1058.     set fontSize 10}
  1059. unset width_    
  1060.  
  1061. proc makeFrame { w type } {
  1062.     global   writefile doExit fontSize buttonfont ws_openMath   
  1063.     set win $w
  1064.     if { "$w" == "." } {
  1065.         set w "" } else {
  1066.         catch { destroy $w}
  1067.         
  1068.         frame $w
  1069.         # toplevel $w
  1070.         # set w $w.new
  1071.             # frame $w
  1072.            # puts "making $w"    
  1073.         
  1074.     }
  1075.  
  1076.     set dismiss "destroy $win"
  1077.     catch { set  parent [winfo parent $win] 
  1078.     if { "$parent" == "." } {
  1079.     set dismiss "destroy ."
  1080.     }
  1081.     if { [string match .plot* [winfo toplevel $win]] } {
  1082.     set dismiss "destroy [winfo toplevel $win]"
  1083.     }
  1084.     }
  1085.     
  1086.     if { "$doExit" != "" } {set dismiss $doExit }     
  1087.     oset $w type $type
  1088.  
  1089.     frame $w.grid
  1090.    #positionWindow $w
  1091.     set c $w.c
  1092.     oset $win c $c
  1093.     bboxToRadius $win
  1094.     
  1095.     if { [catch { set buttonfont} ] } {
  1096.     set buttonfont [font create -family Helvetica -size $fontSize]
  1097.     }
  1098.     set buttonFont $buttonfont    
  1099.     oset $win buttonFont $buttonfont
  1100.  
  1101. #    puts "children wb=[winfo children $w]"
  1102.     set wb $w.buttons
  1103.     frame $wb
  1104.     set dismiss [concat $dismiss "; clearLocal $win "]
  1105.  
  1106.     button $wb.dismiss -text Dismiss -command $dismiss -font $buttonFont
  1107.     setBalloonhelp $win $wb.dismiss {Close this plot window}
  1108.     button $wb.zoom -text "Zoom" -command "showZoom $w" -font $buttonFont
  1109.     setBalloonhelp $win $wb.zoom {Magnify the plot.  Causes clicking with the left mouse button on the plot, to magnify (zoom in) the plot where you click.  Also causes Shift+Click to  it to unmagnify (zoom out) at that point}
  1110.     oset $w position "" 
  1111. #    button $w.position -textvariable [oloc $w position] -font $buttonFont -width 10
  1112.     label $w.position  -textvariable [oloc $w position] -font $buttonFont -width 10
  1113.     setBalloonhelp $win $w.position {Position of the pointer in real x y coordinates.  For 3d it is the position of the nearest vertex of the polygon the pointer is over.}
  1114.  
  1115.     button $wb.help -text "Help" -command "doHelp$type $win" -font $buttonFont
  1116.     setBalloonhelp $win $wb.help {Give more help about this plot window}
  1117.     button $wb.postscript -textvariable writefile -command "writePostscript $w" -font $buttonFont
  1118.     setBalloonhelp $win $wb.postscript {Prints or Saves the plot in postscript format.  The region to be printed is marked using Mark.   Other print options can be obtained by using "Print Options" in the Config menu }
  1119.     
  1120.     button $wb.markrect -text "Mark" -command "markToPrint $c printrectangle \[eval \[oget $win maintitle\]\]" -font $buttonFont
  1121.     setBalloonhelp $win $wb.markrect {Mark the region to be printed.  Causes the left mouse button to allow marking of a rectangle by clicking at the upper left corner, and dragging the mouse to the lower right corner.  The title can be set under "Print Options" under Config}
  1122.     button $wb.replot -text "Replot" -command "replot$type $win" -font $buttonFont
  1123.     setBalloonhelp $win $wb.replot {Use the current settings and recompute the plot.  The settings may be altered in Config}
  1124.     
  1125.     
  1126.     
  1127.     button $wb.config -text "Config" -command "doConfig$type $win" -font $buttonFont
  1128.     setBalloonhelp $win $wb.config {Configure various options about the plot window.  After doing this one may do replot.  Hint: you may leave the config menu on the screen and certain actions take place immediately, such as rotating or computing a trajectory at a point.  To make room for the window you might slide the graph to the right, and possibly shrink it using the unzoom feature}    
  1129.     
  1130.  
  1131.  
  1132.     bind $win.position <Enter> "+place $win.buttons -in $win.position -x 0 -rely 1.0 ;  after cancel lower $win.position ; raise $win.buttons "
  1133.     bind $win.buttons <Leave> "deleteBalloon $c ; place forget $win.buttons"
  1134.  
  1135.     # pack $wb
  1136.     scrollbar $w.hscroll -orient horiz -command "$c xview"
  1137.     scrollbar $w.vscroll -command "$c yview"
  1138.     # -relief sunken
  1139.     canvas $c  -borderwidth 2 \
  1140.         -scrollregion {-1200 -1200 1200 1200} \
  1141.     -xscrollcommand "$w.hscroll set" \
  1142.     -yscrollcommand "$w.vscroll set" -cursor arrow -background white
  1143.     # puts "$c config  -height [oget $win height] -width [oget $win width] "
  1144.     set buttonsLeft 1
  1145.     set wid [oget $win width]
  1146.     catch {$c config  -height [oget $win height] -width  $wid
  1147.            oset $win oldCheight [oget $win height]
  1148.            oset $win oldCwidth $wid
  1149.      }
  1150.     # puts "$c height =[$c cget   -height],$c width =[$c cget   -width]"
  1151.     # bind $c <2> "$c scan mark %x %y"
  1152.     bind $c <B3-Motion> "$c scan dragto %x %y"
  1153.     bind $c <3> "$c scan mark %x %y"
  1154.     bind $c <B3-Motion> "$c scan dragto %x %y"    
  1155.     bind $c <Motion> "showPosition $w %x %y"
  1156.     bind $c <Configure> "reConfigure $c %w %h"
  1157.     bind $c <Enter> "raise $win.position"
  1158.     bind $c <Leave> "after 200 lower $win.position"
  1159.     $w.position config -background [$c cget -background]
  1160.      
  1161.      
  1162.     pack  $wb.dismiss $wb.help $wb.zoom   \
  1163.         $wb.postscript $wb.markrect $wb.replot $wb.config -side top -expand 1 -fill x
  1164.     if { 0 } {
  1165.     pack $w.hscroll -side bottom -expand 1 -fill x
  1166.     pack $w.vscroll -side right -expand 1 -fill y
  1167.     }
  1168.     pack $w.c -side right -expand 1 -fill both
  1169.     
  1170.     pack $w
  1171.     place $w.position -in $w -x 2 -y 2 -anchor nw
  1172.     oset $w position "Menu Here"
  1173.     if { ![info exists ws_openMath(showedplothelp)] ||
  1174.     [llength $ws_openMath(showedplothelp)] < 2 } {
  1175.     lappend ws_openMath(showedplothelp) 1
  1176.     
  1177.     after 100 balloonhelp $w $w.position [list \
  1178.         "Initial help: Moving the mouse over the position \
  1179.         window (top left corner), will bring up a menu.  Holding down \
  1180.         right mouse button and dragging will translate the plot"]
  1181.     after 2000 $w.c delete balloon
  1182.     
  1183.  
  1184.     }
  1185.     
  1186.     raise $w.position
  1187.     
  1188.     pack [winfo parent $wb]
  1189.    # update
  1190. #    set wid [ winfo width $win]
  1191. #    if { $wid > [      $c cget -width ] } {
  1192. #    $c config -width $wid
  1193. #        oset $win width $wid
  1194. #    }
  1195.  
  1196.    addSliders $w 
  1197.  
  1198.    bind $w <Configure> "resizePlotWindow $w %w %h"
  1199.     return $w    
  1200. }
  1201.  
  1202. proc mkentry { newframe textvar text buttonFont } {
  1203.     frame $newframe
  1204.     set parent $newframe
  1205.     set found 0
  1206.     while { !$found } {
  1207.     set parent [winfo parent $parent]
  1208.     if { "$parent" == "" } { break }
  1209.     if { ![catch {  set type [oget $parent type] } ] } {
  1210.         global plot[set type]Options
  1211.         foreach v [set plot[set type]Options] {
  1212.         if { "[oloc $parent [lindex $v 0]]" == "$textvar" } {
  1213.              setBalloonhelp $parent $newframe [lindex $v 2]
  1214.             set found 1
  1215.              break
  1216.  
  1217.         }
  1218.         }
  1219.     }
  1220.     }
  1221.     label $newframe.lab1 
  1222.     label $newframe.lab -text "$text:" -font $buttonFont -width 0
  1223.     entry $newframe.e -width 20 -textvariable $textvar -font $buttonFont
  1224.     pack $newframe.lab1 -side left -expand 1 -fill x 
  1225.     pack $newframe.lab -side left
  1226.     pack $newframe.e -side right -padx 3 -fill x
  1227.    # pack $newframe.lab $newframe.e -side left -padx 3 -expand 1 -fill x
  1228. }
  1229.     
  1230.  
  1231. proc doHelp { win msg } {
  1232.     makeLocal $win c
  1233.     set atx [$c canvasx 0]
  1234.     set aty [$c canvasy 0]
  1235.     $c create rectangle [expr {$atx -1000}] [expr  {$aty -1000}] 10000 10000 -fill white -tag help
  1236.  
  1237.     $c create text [expr {$atx +10}] [expr {$aty + 10.0}] -tag help  -anchor nw  -width 400 -text $msg 
  1238.  
  1239.     pushBind $c <1> "$c delete help; popBind $c <1>"
  1240. }
  1241.  
  1242. ## source push.tcl
  1243.  
  1244. ###### push.tcl ######
  1245. ############################################################
  1246. # Netmath       Copyright (C) 1998 William F. Schelter     #
  1247. # For distribution under GNU public License.  See COPYING. # 
  1248. ############################################################
  1249.  
  1250.  
  1251.  
  1252. #
  1253.  #-----------------------------------------------------------------
  1254.  #
  1255.  # pushl --  push VALUE onto a stack stored under KEY
  1256.  #
  1257.  #  Results:
  1258.  #
  1259.  #  Side Effects: 
  1260.  #
  1261.  #----------------------------------------------------------------
  1262. #
  1263.  
  1264. global __pushl_ar
  1265. proc pushl { val key  } {
  1266.     global __pushl_ar
  1267.   append __pushl_ar($key) " [list $val]"
  1268. }
  1269.  
  1270.  
  1271. #
  1272.  #-----------------------------------------------------------------
  1273.  #
  1274.  # peekl --  if a value has been pushl'd under KEY return the 
  1275.  # last value otherwise return DEFAULT.   If M is supplied, get the
  1276.  # M'th one pushed... M == 1 is the last one pushed.
  1277.  #  Results:  a previously pushed value or DEFAULT
  1278.  #
  1279.  #  Side Effects: none
  1280.  #
  1281.  #----------------------------------------------------------------
  1282. #
  1283. proc peekl {key default {m 1}} {
  1284.     global __pushl_ar
  1285.     if { [catch { set val [set __pushl_ar($key) ] } ] } {
  1286.     return $default } else {
  1287.         set n [llength $val]
  1288.         if { $m > 0 && $m <= $n } {
  1289.         return [lindex $val [incr n -$m]]
  1290.         } else { return $default }
  1291.     }
  1292.     }
  1293.     
  1294.     
  1295.  
  1296. #
  1297.  #-----------------------------------------------------------------
  1298.  #
  1299.  # popl --  pop off  last value stored under KEY, or else return DFLT
  1300.  #
  1301.  #  Results: last VALUE stored or DEFAULT
  1302.  #
  1303.  #  Side Effects: List stored under KEY becomes one shorter
  1304.  #
  1305.  #----------------------------------------------------------------
  1306. #
  1307. proc popl { key  dflt} {
  1308.     global __pushl_ar
  1309.     
  1310.     if { [catch { set val [set __pushl_ar($key) ] } ] } {
  1311.     return $dflt } else {
  1312.         set n [llength $val]
  1313.            set result [lindex $val [incr n -1]]
  1314.  
  1315.         if { $n > 0 } {
  1316.         set __pushl_ar($key) [lrange $val 0 [expr {$n -1}]]
  1317.         } else {unset __pushl_ar($key) }
  1318.         return $result
  1319.     }
  1320.     }
  1321.  
  1322.  
  1323. #
  1324.  #-----------------------------------------------------------------
  1325.  #
  1326.  # clearl --  clear the list stored under KEY
  1327.  # 
  1328.  #  Result: none
  1329.  #
  1330.  #  Side Effects:  clear the list stored under KEY
  1331.  #
  1332.  #----------------------------------------------------------------
  1333. #
  1334. proc clearl { key } {
  1335.     global __pushl_ar
  1336.     catch { unset __pushl_ar($key) }
  1337. }
  1338.     
  1339.  
  1340.  
  1341. ## endsource push.tcl
  1342. proc pushBind { win key action } {
  1343.     pushl [bind $win $key] [list $win $key ] 
  1344.     bind $win $key $action
  1345. }
  1346.  
  1347. proc popBind { win key  } {
  1348.     set binding [popl [list $win $key] {}]
  1349.    
  1350.     bind $win $key $binding
  1351. }
  1352.  
  1353. # exit if not part of openmath browser
  1354. proc maybeExit { n } {
  1355.     if { "[info proc OpenMathOpenUrl]" != "" } {
  1356.     uplevel 1 return
  1357.     } else { exit 0 }
  1358. }
  1359.  
  1360. proc showPosition { win x y } {
  1361.    # global position c
  1362.     makeLocal $win c
  1363.     # we catch so that in case have no functions or data..
  1364.     catch {
  1365.     oset $win position \
  1366.       "[format {(%.2f,%.2f)}  [storx$win [$c canvasx $x]] [story$win [$c canvasy $y]]]"
  1367. }   }
  1368.  
  1369. proc showZoom  { win } {
  1370.   #  global c position
  1371.     makeLocal $win c
  1372.     oset $win position "Click to Zoom\nShift+Click Unzoom"
  1373.      
  1374.     bind $c <1> "doZoom $win %x %y 1"
  1375.     bind $c  <Shift-1> "doZoom $win %x %y -1"
  1376. }
  1377.  
  1378. proc doZoom { win x y direction } {
  1379.     set zf [oget $win zoomfactor]
  1380.     if { $direction < 0 } {
  1381.     set zf     "[expr {1/[lindex $zf 0]}] [expr {1/[lindex $zf 1]}]"
  1382.     }
  1383.     eval doZoomXY $win $x $y $zf
  1384. }
  1385.     
  1386.  
  1387.  
  1388. #
  1389.  #-----------------------------------------------------------------
  1390.  #
  1391.  # doZoomXY --  given screen coordinates (x,y) and factors (f1,f2)
  1392.  #  perform a scaling on the canvas, centered at (x,y) so that
  1393.  #  the distance in the x direction from this origin is multiplied by f1
  1394.  #  and similarly in the y direction
  1395.  #  Results:
  1396.  #
  1397.  #  Side Effects: scale the canvas, and set new transforms for translation
  1398.  #   from real to canvas coordinates.
  1399.  #----------------------------------------------------------------
  1400. #
  1401.  
  1402. proc doZoomXY { win x y facx facy } {
  1403.     if { [catch {
  1404.     makeLocal $win c transform
  1405.     } ] } {
  1406.     # not ready
  1407.     return
  1408.     }
  1409.     
  1410.     set x [$c canvasx $x]
  1411.     set y [$c canvasy $y]
  1412.  
  1413.     $c scale all $x $y $facx $facy
  1414.  
  1415.     set ntransform [composeTransform \
  1416.         "$facx 0 0 $facy [expr {(1-$facx)* $x}] [expr {(1-$facy)* $y}]" \
  1417.         $transform  ]
  1418.     oset $win transform $ntransform
  1419.     getXtransYtrans $ntransform rtosx$win rtosy$win
  1420.     getXtransYtrans [inverseTransform $ntransform] storx$win story$win
  1421.     axisTicks $win $c
  1422. }
  1423.  
  1424.  
  1425. #
  1426.  #-----------------------------------------------------------------
  1427.  #
  1428.  # scrollPointTo --  attempt to scroll the canvas so that point
  1429.  #  x,y on the canvas appears at screen (sx,sy)
  1430.  #
  1431.  #  Results: none
  1432.  #
  1433.  #  Side Effects: changes x and y view of canvas 
  1434.  #
  1435.  #----------------------------------------------------------------
  1436. #
  1437. proc scrollPointTo { c x y sx sy } {
  1438.     desetq "x0 y0 x1 y1" [$c cget -scrollregion]
  1439.     $c xview moveto [expr { 1.0*($x-$x0-$sx)/($x1-$x0)} ]
  1440.     $c yview moveto [expr { 1.0*($y-$y0-$sy)/($y1-$y0)} ]
  1441. }
  1442.  
  1443.  
  1444.  
  1445. #
  1446.  #-----------------------------------------------------------------
  1447.  #
  1448.  # reConfigure --  
  1449.  #
  1450.  #  Results:
  1451.  #
  1452.  #  Side Effects: 
  1453.  #
  1454.  #----------------------------------------------------------------
  1455. #
  1456.  
  1457. proc reConfigure { c width height  } {
  1458.     set w [winfo parent $c]
  1459.     if { [catch { makeLocal $w oldCwidth oldCheight } ] } {
  1460.     oset $w oldCwidth $width
  1461.     oset $w oldCheight $height
  1462.     return
  1463.     }
  1464.     set oldx [$c canvasx [expr {$oldCwidth/2.0}]]
  1465.     set oldy [$c canvasy [expr {$oldCheight/2.0}]]
  1466.     doZoomXY $w [expr {$oldCwidth/2.0}] [expr {$oldCheight/2.0}] \
  1467.         [expr {1.0*$width/$oldCwidth}] [expr {1.0*$height/$oldCheight}]
  1468.     
  1469.     scrollPointTo $c $oldx $oldy [expr {$width/2.0}] [expr {$height/2.0}]
  1470.    # update
  1471.     oset $w oldCwidth $width
  1472.     oset $w oldCheight $height
  1473. }
  1474.  
  1475. proc writePostscript { win } {
  1476.     global  printOption argv
  1477.     makeLocal $win c transform transform0 xmin ymin xmax ymax
  1478.     set rtosx rtosx$win ; set rtosy rtosy$win
  1479.     drawPointsForPrint $c
  1480.     if { "[$c find withtag printrectangle]" == "" } {
  1481.     # $c create rectangle [$rtosx $xmin] [$rtosy $ymin] [$rtosx $xmax] [$rtosy $ymax] -tags printrectangle -width .5
  1482.     $c create rectangle [$c canvasx 0] [$c canvasy 0] [$c canvasx [$c cget -width ]] [$c canvasy [$c cget -height ]]   -tags printrectangle -width .5    
  1483.     unbindAdjustWidth $c printrectangle [eval [oget $win maintitle]]
  1484.     }
  1485.     $c delete balloon
  1486.     
  1487.     
  1488.     set bbox [eval $c bbox [$c find withtag printrectangle]]
  1489.     desetq "x1 y1 x2 y2" $bbox
  1490. #     set title "unknown plot"
  1491. #     catch { set title [eval $printOption(maintitle)] }
  1492.  
  1493. #     $c create text [expr {($x1 + $x2)/2}]  [expr {$y1 + .04 * ($y2 - $y1)}] \
  1494. #         -anchor center -text $title -tag title
  1495.  
  1496.     update
  1497. set diag [vectorlength [expr {$y1-$x1}] [expr {$y2-$x2}]]
  1498. #  get rid of little arrows that creep onto the outside, ie let
  1499. #  the blank rectangle cover them.
  1500. set x1 [expr {$x1+.01 * $diag}]
  1501. set x2 [expr {$x2-.01 * $diag}]
  1502. set y1 [expr {$y1+.01 * $diag}]
  1503. set y2 [expr {$y2-.01 * $diag}]
  1504.  
  1505.     set com "$c postscript  \
  1506.               -x  $x1  -y $y1 \
  1507.         -width [expr {($x2 - $x1)}] \
  1508.             -height [expr {($y2 - $y1)}] \
  1509.         [getPageOffsets [expr {($x2 - $x1)/(1.0*($y2 - $y1))}] ] "
  1510.  
  1511.     #puts com=$com
  1512.     set output [eval $com]
  1513.     switch $printOption(tofile) {
  1514.     0 { global tcl_platform
  1515.         set usegsview 0  
  1516.         if { "$tcl_platform(platform)" == "windows" } {
  1517.         set usegsview 1
  1518.         }
  1519.         if { $usegsview } {
  1520.         set fi [open $printOption(psfilename) w]
  1521.         puts $fi $output
  1522.         close $fi
  1523.         exec "$printOption(gsview) /S $printOption(psfilename)"
  1524.         } else {
  1525.         set fi [open "|lpr -P[set printOption(printer)]" w]
  1526.         puts $fi $output
  1527.         close $fi
  1528.         }
  1529.     }
  1530.     1 { set fi [open $printOption(psfilename) w]
  1531.     puts $fi $output
  1532.     close $fi }
  1533.     2 { global ftpInfo
  1534.         set ftpInfo(data) $output
  1535.         ftpDialog $win
  1536.     }
  1537.     }
  1538. #    if { $printOption(tofile) } {
  1539. #    set fi [open $printOption(psfilename) w]
  1540. #    } else { set fi [open "|lpr -P[set printOption(printer)]" w] }
  1541.  #   puts $fi $output
  1542. #    close $fi
  1543. }
  1544.  
  1545.  
  1546. #
  1547.  #-----------------------------------------------------------------
  1548.  #
  1549.  # ftpDialog --  open up a dialog to send ftpInfo(data) to a file
  1550.  # via http and ftp.   The http server can be specified.
  1551.  #
  1552.  #  Results:
  1553.  #
  1554.  #  Side Effects: 
  1555.  #
  1556.  #----------------------------------------------------------------
  1557. #
  1558.  
  1559. set ftpInfo(host) genie1.ma.utexas.edu
  1560. set ftpInfo(viahost) genie1.ma.utexas.edu
  1561.  
  1562. proc ftpDialog { win args } {
  1563.     global ftpInfo buttonFont fontSize
  1564.     set fr ${win}plot
  1565.     set usefilename [assoc -filename $args  0]
  1566.     if { "$usefilename" != "0"} {
  1567.     set ftpInfo(filename) $usefilename
  1568.     set usefilename 1
  1569.     }
  1570.     catch { destroy $fr }
  1571.     set ftpInfo(percent) 0
  1572.     set buttonFont [font create -family Courier -size $fontSize]
  1573.     frame $fr -borderwidth 2 -relief raised
  1574.     if { [catch { set ftpInfo(directory) } ] } { set ftpInfo(directory) homework }
  1575.     label $fr.title -text "Ftp Dialog Box" -font [font create -family Helvetica -size [expr {2+ $fontSize}]]
  1576.     mkentry $fr.host ftpInfo(host) "host to write file on" $buttonFont
  1577.     mkentry $fr.viahost ftpInfo(viahost) "host to write to via" $buttonFont
  1578.     mkentry $fr.username ftpInfo(username) "Your User ID on host" $buttonFont
  1579.     mkentry $fr.password ftpInfo(password) "Your password on host" $buttonFont
  1580.     $fr.password.e config -show *
  1581.     mkentry $fr.directory ftpInfo(directory) "remote subdirectory for output" $buttonFont
  1582.  
  1583.     if { $usefilename } {
  1584.     mkentry $fr.filename ftpInfo(filename) "filename " $buttonFont
  1585.     } else {
  1586.     mkentry $fr.chapter ftpInfo(chapter) "chapter " $buttonFont
  1587.     mkentry $fr.section ftpInfo(section) "section" $buttonFont
  1588.     mkentry $fr.problemnumber ftpInfo(number) "Problem number" $buttonFont
  1589.     }
  1590.     scale   $fr.scale -orient horizontal -variable ftpInfo(percent) -length 100 
  1591.     button $fr.doit -text "Send it" -command "doFtpSend $fr" -font $buttonFont
  1592.     button $fr.cancel -text "Cancel" -command "destroy $fr" -font $buttonFont
  1593.     set ftpInfo(message) ""
  1594.     label $fr.message  -width 30 -height 3 -textvariable ftpInfo(message) -font $buttonFont
  1595.     eval pack  [winfo  children $fr] -side top 
  1596.     raise $fr
  1597.     place $fr -in $win -relx .5 -rely .5 -anchor center
  1598.    }
  1599.  
  1600. proc doFtpSend { fr } {
  1601.     global ftpInfo om_ftp
  1602.     set error ""
  1603.     if { [winfo exists $fr.filename] } {
  1604.     set filename $ftpInfo(filename)
  1605.     set check "host username directory filename"
  1606.     } else {
  1607.     set check "host username directory chapter section number"
  1608.     }
  1609.     foreach v $check {
  1610.     if { $ftpInfo($v) == "" } {
  1611.         if  { "$error" == "" } { set error "Failed to specify $v " } else {
  1612.         append error ", $v"}
  1613.     }   
  1614.     }
  1615.     if { "$error" != "" } {
  1616.     set ftpInfo(message) $error
  1617.     return -1
  1618.     }
  1619.     if { [winfo exists $fr.chapter] } {
  1620.     set filename "$ftpInfo(chapter).$ftpInfo(section)-$ftpInfo(number).ps"
  1621.     }
  1622.     
  1623.     
  1624.     set res [submitFtp $ftpInfo(viahost) $ftpInfo(host) $ftpInfo(username) $ftpInfo(password) $ftpInfo(directory) $filename]
  1625.     if { "$res" == 1 }  {
  1626.        after 1000 "destroy $fr"
  1627.     }
  1628.     return $res
  1629.     
  1630. #    set counter [ ftp $ftpInfo(host) $ftpInfo(username) $ftpInfo(password)]
  1631. #    if { $counter < 0 } {
  1632. #    set ftpInfo(message) [concat "Failed:" $om_ftp($counter,log)]
  1633. #    return -1
  1634. #    }
  1635.  
  1636. #     if { [ftpDoCd $counter $ftpInfo(directory)] < 0 &&
  1637. #          [ftpDoMkdir $counter $ftpInfo(directory)] > -10 &&
  1638. #        [ftpDoCd $counter $ftpInfo(directory)] < 0 } {
  1639. #     set ftpInfo(message) [concat "Failed:" $om_ftp($counter,log)]
  1640. #     return -1
  1641. #     }
  1642.  
  1643.     
  1644. #     set res [ftpDoStore $counter $ftpInfo(chapter).$ftpInfo(section)-$ftpInfo(number).ps $ftpInfo(data)]
  1645. #     if { $res < 0 } {
  1646. #     set ftpInfo(message) "Failed: $om_ftp($counter,log)"
  1647. #     return -1
  1648. #     } else {
  1649. #     set ftpInfo(message) "Wrote $ftpInfo(directory)/$ftpInfo(chapter).$ftpInfo(section)-$ftpInfo(number).ps"
  1650. #     after 1000 destroy $fr
  1651. #     }
  1652. #     ftpClose $counter
  1653. }
  1654.  
  1655. proc vectorlength { a b } {
  1656.     return [expr {sqrt($a*$a + $b * $b)} ]
  1657. }
  1658.  
  1659. proc setupCanvas { win } {
  1660.   makeLocal $win   xcenter xradius ycenter yradius
  1661.  
  1662.   oset $win xmin [expr {$xcenter - $xradius}]
  1663.   oset $win xmax [expr { $xcenter + $xradius}]
  1664.   oset $win ymin [expr { $ycenter - $yradius}]
  1665.   oset $win ymax [expr { $ycenter + $yradius} ]
  1666.  
  1667. }
  1668.  
  1669.  
  1670. #
  1671.  #-----------------------------------------------------------------
  1672.  #
  1673.  # compose --  A and B are transformations of the form "origin scalefac"
  1674.  # and composing them means applying first b then a, as in a.b.x
  1675.  #  "o s" . x ==> (x-o)*s + o
  1676.  #  Results: the "origin scalefac" which corresponds to the composition.
  1677.  #
  1678.  #  Side Effects: 
  1679.  #
  1680.  #----------------------------------------------------------------
  1681. #
  1682. proc compose { a b } {
  1683.   return  "[expr {-[lindex $a 1]*[lindex $b 0]*[lindex $b 1] \
  1684.       +[lindex $a 1]*[lindex $b 0]-[lindex $a 0]*[lindex $a 1] \
  1685.       +[lindex $a 0]}] [expr {[lindex $a 1]*[lindex $b 1]}]"
  1686. }
  1687.  
  1688. # the following two have been replaced 
  1689. # proc sparseList { s } {
  1690. #     if  { [catch {
  1691. #     set val [parseConvert "$s" -variables "x y t"] } err ] } {
  1692. #         error "Syntax error with `$s'\n $err"
  1693. #     }
  1694. #     return [lindex $val 0]
  1695. #     }
  1696. # proc sparse { s } {
  1697. #     set val [sparseList $s]
  1698. #     set first $val
  1699. #     if { [llength $first] != 1 } {
  1700. #     error "only one function wanted" }
  1701. #     
  1702. #     return [lindex $first 0]
  1703. #    }
  1704.  
  1705. proc sparseListWithParams { form variables paramlist } {
  1706.     set tem [parseConvert $form -doall 1]
  1707.     #puts tem=$tem
  1708.     set params [splitParams $paramlist]
  1709.     if { [catch {set res [substParams [lindex $tem 0] $variables $params] }\
  1710.         err ] } {
  1711.     set vars [lindex $tem 1]
  1712.     set all $variables
  1713.     foreach { v val }  $params { lappend all $v}
  1714.     foreach v $vars { if { [lsearch $all [string range $v 1 end]] < 0 } {
  1715.         error "The variable `[string range $v 1 end]' appeared in $form but was not in allowed variables:{$variables} or in parameters: {$paramlist}"
  1716.     }
  1717.     }
  1718.     error "The form $form may involve variables other than {$variables} or the parameters {$paramlist}, or the latter may have invalid expressions:\n $err"
  1719.     }
  1720.     return $res
  1721. }
  1722.  
  1723. proc sparseWithParams { form variables params } {
  1724.     set tem [sparseListWithParams $form $variables $params]
  1725.     if { [llength $tem ] > 1 } { error "only wanted one function: $form"}
  1726.     lindex $tem 0
  1727. }
  1728.  
  1729.  
  1730.  
  1731. #
  1732.  #-----------------------------------------------------------------
  1733.  #
  1734.  # myVarSubst --  into FORM substitute where
  1735.  # listVarsVals where each element of this list may mention
  1736.  # the previous values eg "k 7 ll sin(k+8)"
  1737.  # eg:
  1738.  #myVarSubst [lindex [parseConvert "k*x+l" -doall 1] 0] {x $x k 27+4 l 93+k^3}
  1739.  # ==> {((31 * $x) + 29884.0)}  
  1740.  #
  1741.  #  Results: FORM with the substitutions done
  1742.  #
  1743.  #  Side Effects: 
  1744.  #
  1745.  #----------------------------------------------------------------
  1746. #
  1747. proc myVarSubst { form listVarsVals } {
  1748.     foreach {_u _v} $listVarsVals {
  1749.     if { "\$$_u" == "$_v" } {
  1750.         set $_u $_v
  1751.     } else {
  1752.         set _f1 [lindex [parseConvert  $_v -doall 1] 0]
  1753.         set $_u [expr [lindex $_f1 0]]
  1754.         # puts "$_u = [set $_u]"
  1755.     }
  1756.    }
  1757.    subst -nobackslashes -nocommands $form
  1758.  
  1759. }
  1760.  
  1761. proc splitParams { paramlist } {
  1762.     set params ""
  1763.     foreach v [split $paramlist ,] {
  1764.     set tem [split $v =]
  1765.     if { [llength $tem] == 2 } {
  1766.         lappend params [lindex $tem 0] [lindex $tem 1]
  1767.     }
  1768.     }
  1769.     return $params
  1770. }
  1771.  
  1772.     
  1773.  
  1774. #
  1775.  #-----------------------------------------------------------------
  1776.  #
  1777.  # substParams --  substitute into FORM keeping VARIABLES as they are
  1778.  # and the PARAMLIST (of the form k=23, l=k+7,...) into FORM
  1779.  #
  1780.  #  Results: substituted FORM
  1781.  #
  1782.  #  Side Effects: none
  1783.  #
  1784.  #----------------------------------------------------------------
  1785. #
  1786. proc substParams { form variables params } {
  1787.    foreach v $variables { lappend params $v \$$v}
  1788.    set res [myVarSubst $form $params]
  1789.     return $res
  1790. }
  1791.     
  1792.     
  1793.     
  1794.  
  1795.  
  1796. #
  1797.  #-----------------------------------------------------------------
  1798.  #
  1799.  # setUpTransforms --  set up transformations for the canvas of WINDOW
  1800.  # so that the image is on FACTOR fractionof the window
  1801.  # these transforms are used for real to screen and vice versa.
  1802.  #  Results: 
  1803.  #
  1804.  #  Side Effects: transform functions rtosx$win rtosy$win storx$win story$win
  1805.  #  are defined.
  1806.  #
  1807.  #----------------------------------------------------------------
  1808. #    
  1809. proc setUpTransforms { win fac } {
  1810.     makeLocal $win xcenter ycenter xradius yradius c
  1811.  
  1812.     set delx [$c cget -width]
  1813.     set dely [$c cget -height]
  1814.     set f1 [expr {(1 - $fac)/2.0}]
  1815.     
  1816.     set x1 [expr {$f1 *$delx}]
  1817.     set y1 [expr {$f1 *$dely}]
  1818.     set x2 [expr {$x1 + $fac*$delx}]
  1819.     set y2 [expr {$x1 + $fac*$dely}]
  1820.  
  1821.     
  1822.     
  1823.     set xmin [expr {$xcenter - $xradius}]
  1824.     set xmax [expr {$xcenter + $xradius}]
  1825.     set ymin [expr {$ycenter - $yradius}]
  1826.     set ymax [expr {$ycenter + $yradius}]
  1827.     
  1828.     oset $win xmin $xmin
  1829.     oset $win xmax $xmax
  1830.     oset  $win ymin $ymin
  1831.     oset $win ymax $ymax
  1832.     
  1833.     oset $win transform [makeTransform "$xmin $ymin $x1 $y2" "$xmin $ymax $x1 $y1 " "$xmax $ymin $x2 $y2"]
  1834.     set transform [makeTransform "$xmin $ymin $x1 $y2" "$xmin $ymax $x1 $y1 " "$xmax $ymin $x2 $y2"]
  1835.     oset $win transform $transform
  1836.     oset $win transform0 $transform
  1837.     
  1838.     getXtransYtrans $transform rtosx$win rtosy$win
  1839.     getXtransYtrans [inverseTransform $transform] storx$win story$win 
  1840.     
  1841. }
  1842.  
  1843. proc inputParse { in } {
  1844.   if { [regexp -indices \
  1845.        {D\[([a-zA-Z][0-9a-zA-Z]*[ ]*),([a-zA-Z][0-9a-zA-Z]*[ ]*)\] *=} \
  1846.       $in all1 i1 i2] } {
  1847.    set v1 [getOneMatch $in $i1]
  1848.    set v2 [getOneMatch $in $i2]
  1849.    set s1 [string range $in [lindex $all1 1] end]
  1850.  
  1851.      if { [regexp -indices {,[ \n]*D\[([a-zA-Z][0-9a-zA-Z]*[ ]*),([a-zA-Z][0-9a-zA-Z]*[ ]*)\] *=} \
  1852.       $s1 all2 i1 i2] } {
  1853.    set v3  [getOneMatch $s1 $i1]
  1854.    set v4 [getOneMatch $s1 $i2]
  1855.    set end [string first \} $s1 ]
  1856.       set form2 [string range $s1 [expr {1 + [lindex $all2 1]}] [expr {$end -1}]]
  1857.     if { "$v4" != "$v2" } {error "different variable $v2 and $v4"}
  1858.  
  1859.     set form1 [string range $in [expr {1 + [lindex $all1 1]}] [expr {[lindex $all2 0] + -1 + [lindex $all1 1]}]]
  1860.     return [list  $v2 $v1 $v3 $form1 $form2]
  1861.     # puts "v1=$v1,form1=$form1,form2=$form2"  
  1862.   } 
  1863.  }
  1864. }
  1865.  
  1866. proc composeTransform { t1 t2  } {
  1867.     desetq "a11 a12 a21 a22 e1 e2" $t1
  1868.     desetq "b11 b12 b21 b22 f1 f2" $t2
  1869.    return  [list \
  1870.        [expr {$a11*$b11+$a12*$b21}] \
  1871.        [expr {$a11*$b12+$a12*$b22}] \
  1872.        [expr {$a21*$b11+$a22*$b21}] \
  1873.        [expr {$a22*$b22+$a21*$b12}] \
  1874.        [expr {$a11*$f1+$a12*$f2+$e1}] \
  1875.        [expr {$a21*$f1+$a22*$f2+$e2}] ]
  1876. }
  1877.     
  1878.  
  1879.  
  1880. #
  1881.  #-----------------------------------------------------------------
  1882.  #
  1883.  # makeTransform --  Given three points mapped to three other points
  1884.  # write down the affine transformation (A.X+B) which performs this.
  1885.  # the arguments are of the form "x1 y1 u1 v1" "x2 y2 u2 v2" "x3 y3 u3 v3"
  1886.  # where (x1,y1) --> (u1,v1)  etc.
  1887.  #  Results: an affine transformation "a b c d e f" which is
  1888.  #     [ a  b ]  [ x1 ] + [ e ]     
  1889.  #     [ c  d ]  [ y1 ]   [ f ]
  1890.  #  Side Effects: none
  1891.  #
  1892.  #----------------------------------------------------------------
  1893. #
  1894. proc makeTransform { P1 P2 P3 } {
  1895.     desetq  "X1 Y1 U1 V1" $P1
  1896.     desetq  "X2 Y2 U2 V2" $P2
  1897.     desetq  "X3 Y3 U3 V3" $P3
  1898.     set tem [expr {double((($X2-$X1)*$Y3+($X1-$X3)*$Y2+($X3-$X2)*$Y1))}]
  1899.     set A [expr {(($U2-$U1)*$Y3+($U1-$U3)*$Y2+($U3-$U2)*$Y1) \
  1900.         /$tem}]
  1901.     set B [expr {-(($U2-$U1)*$X3+($U1-$U3)*$X2+($U3-$U2)*$X1) \
  1902.         /$tem}]
  1903.     set E [expr {(($U1*$X2-$U2*$X1)*$Y3+($U3*$X1-$U1*$X3)*$Y2+($U2*$X3-$U3*$X2)*$Y1) \
  1904.         /$tem}]
  1905.     set C [expr {(($V2-$V1)*$Y3+($V1-$V3)*$Y2+($V3-$V2)*$Y1) \
  1906.         /$tem}]
  1907.     set D [expr {-(($V2-$V1)*$X3+($V1-$V3)*$X2+($V3-$V2)*$X1) \
  1908.         /$tem}]
  1909.     set F [expr {(($V1*$X2-$V2*$X1)*$Y3+($V3*$X1-$V1*$X3)*$Y2+($V2*$X3-$V3*$X2)*$Y1) \
  1910.         /$tem}]
  1911.     set xf ""
  1912.     set yf ""
  1913.     if { $B == 0  && $C == 0 } {
  1914.     set xf "$A*\$X+$E"
  1915.     set yf "$D*\$Y+$F"
  1916.     }
  1917.     return [list $A $B $C $D $E $F]
  1918. }
  1919.  
  1920.  
  1921. #
  1922.  #-----------------------------------------------------------------
  1923.  #
  1924.  # getXtransYtrans --   If the x coordinate transforms independently
  1925.  #  of the y and vice versa, give expressions suitable for building a
  1926.  # proc. 
  1927.  #  Results:
  1928.  #
  1929.  #  Side Effects: 
  1930.  #
  1931.  #----------------------------------------------------------------
  1932. #
  1933. proc getXtransYtrans { transform p1 p2 } {
  1934.     desetq "a b c d e f"  $transform
  1935.     if { $b == 0  && $c == 0 } {
  1936.     proc $p1 { x } "return \[expr {$a*\$x+$e}\]" 
  1937.     proc $p2 { y } "return \[expr {$d*\$y+$f} \]"
  1938.     return 1
  1939.     }
  1940.     return 0
  1941. }
  1942.  
  1943.  
  1944. #
  1945.  #-----------------------------------------------------------------
  1946.  #
  1947.  # inverseTransform --   Find the inverse of an affine transformation.
  1948.  #
  1949.  #  Results:
  1950.  #
  1951.  #  Side Effects: 
  1952.  #
  1953.  #----------------------------------------------------------------
  1954. #
  1955. proc inverseTransform { transform } {
  1956.     desetq "a b c d e f" $transform
  1957.     set det [expr {double($a*$d - $b*$c)}]
  1958.     return [list [expr {$d/$det}] [expr {- $b / $det }] [expr {- $c / $det}] [expr {$a / $det}]  [expr {($b*$f-$d*$e)/ $det }] [expr {-($a*$f-$c*$e)/ $det}]]
  1959.  
  1960. }
  1961.  
  1962.  
  1963. #
  1964.  #-----------------------------------------------------------------
  1965.  #
  1966.  # getTicks --  given an interval (a,b) subdivide it and 
  1967.  # calculate where to put the ticks and what to print there.
  1968.  # we want DESIRED number of ticks, but we also want the ticks
  1969.  # to be at points in the real coords of the form .2*10^i or .5*10^j
  1970.  #  Results: the ticks
  1971.  #
  1972.  #  Side Effects: 
  1973.  #
  1974.  #----------------------------------------------------------------
  1975. #
  1976.  
  1977. proc getTicks { a b n } {
  1978.     set len [expr {(($b - $a))}]
  1979.     if { $len < [expr {pow(10,-40)}] } { return ""}
  1980.     set best 0
  1981.     foreach v { .1 .2 .5 } {
  1982.     # want $len/(.1*10^i) == $n
  1983.     set val($v)  [expr {ceil(log10($len/(double($n)*$v)))}]
  1984.     set use [expr {$v*pow(10,$val($v))}]
  1985.     set fac [expr {1/$use}]
  1986.     set aa [expr {$a * $fac + .03}]
  1987.     set bb [expr {$b * $fac -.03}]
  1988.     set j [expr {round(ceil($aa)) }]
  1989.     set upto [expr {floor($bb) }]
  1990.     set ticks ""
  1991.     while { $j <= $upto } {
  1992.         set tt [expr {$j / $fac}]
  1993.         if { $j%5 == 0 } {
  1994.         append ticks " { $tt $tt }"
  1995.         } else  {
  1996.         append ticks " $tt"
  1997.         }
  1998.         incr j   
  1999.     }
  2000.     set answer($v) $ticks
  2001.     set this [llength $ticks]
  2002.     if { $this  > $best } {
  2003.         set best $this
  2004.         set at $v
  2005.     }
  2006.     #puts "for $v [llength $ticks] ticks"
  2007.     }
  2008.     #puts "using $at [llength $answer($at)]"
  2009.      
  2010.     return $answer($at)
  2011. }
  2012.      
  2013. proc axisTicks { win c }  {
  2014.     $c delete axisTicks
  2015.     if { ![catch {oget $win noaxisticks}] } { return }
  2016.     set swid [$c cget -width]
  2017.     set shei [$c cget -height]
  2018.     set x1 [storx$win [$c canvasx 0]]
  2019.     set y1 [story$win [$c canvasy 0]]
  2020.     set x2 [storx$win [$c canvasx $swid]]
  2021.     set y2 [story$win [$c canvasy $shei]]
  2022.     #puts "x1=$x1,y1=$y1,y2=$y2,x2=$x2"
  2023.     if { $y1 > 0  &&  $y2 < 0 } {
  2024.     set ticks [getTicks $x1 $x2 [expr {$swid/50}] ]
  2025.     #puts "ticks=$ticks"
  2026.     set eps [expr {.005 * abs($y1 - $y2)}]
  2027.     set neps [expr {-.005 * abs($y1 - $y2)}]
  2028.     set donext 0
  2029.     foreach v $ticks {
  2030.         set x [lindex $v 0]
  2031.         set text [lindex $v 1]
  2032.         if { $donext } {set text [lindex $v 0] ; set donext 0 }
  2033.         if { [lindex $v 0] == 0 } { set text "" ; set donext 1 }
  2034.         #puts " drawTick $c $x 0 0 $neps 0 $eps  $text axisTicks"
  2035.         drawTick $c $x 0 0 $neps 0 $eps  $text axisTicks
  2036.         }
  2037.     }
  2038.     if { 0 < $x2 && 0 > $x1 } {
  2039.     set ticks [getTicks $y2 $y1 [expr {$shei/50}]]
  2040.     set eps [expr {.005 * ($x2 - $x1)}]
  2041.     set neps [expr {-.005 * ($x2 - $x1)}]
  2042.     set donext 0
  2043.     foreach v $ticks {
  2044.         set y [lindex $v 0]
  2045.         set text [lindex $v 1]
  2046.         if { $donext } {set text [lindex $v 0] ; set donext 0}
  2047.         if { [lindex $v 0] == 0 } { set text "" ; set donext 1}
  2048.  
  2049.         drawTick $c 0 $y $neps 0 $eps 0  $text axisTicks
  2050.         }
  2051.     }
  2052.  
  2053.     }
  2054.  
  2055.  
  2056. #
  2057.  #-----------------------------------------------------------------
  2058.  #
  2059.  # marginTicks --  draw ticks around the border of window
  2060.  #  x1,y1  top left x2,y2 bottom right.
  2061.  #
  2062.  #  Results:
  2063.  #
  2064.  #  Side Effects: 
  2065.  #
  2066.  #----------------------------------------------------------------
  2067. #    
  2068. proc marginTicks { c x1 y1 x2 y2 tag }  {
  2069.     global printOption
  2070.     set win [winfo parent $c]
  2071.  
  2072.     if { ![catch {oget $win noaxisticks}] } { return }
  2073.     $c delete marginTicks
  2074.     set ticks [getTicks $x1 $x2 $printOption(xticks)]
  2075.     # puts "x=$x1 $x2"
  2076.     set eps [expr {.008 * ($y1 - $y2)}]
  2077.     set neps [expr {-.008 * ($y1 - $y2)}]
  2078.     foreach v $ticks {
  2079.     set x [lindex $v 0]
  2080.     set text [lindex $v 1]
  2081.     drawTick $c $x $y1 0 0 0 $neps  $text $tag
  2082.     drawTick $c $x $y2 0 0 0 $eps  $text $tag
  2083.     
  2084.     }
  2085.     #puts "y=$y2,$y1"
  2086.     set ticks [getTicks $y1 $y2 $printOption(yticks)]
  2087.     set eps [expr {.005 * ($x2 - $x1)}]
  2088.     set neps [expr {-.005 * ($x2 - $x1)}]
  2089.     set donext 0
  2090.     foreach v $ticks {
  2091.     set y [lindex $v 0]
  2092.     set text [lindex $v 1]
  2093.     drawTick $c $x1 $y 0 0 $eps 0  $text $tag
  2094.     drawTick $c $x2 $y 0 0 $neps 0  $text $tag
  2095.         }
  2096.     }
  2097.  
  2098. proc drawTick {c x y dx dy ex ey n tags} {
  2099.     global axisGray     fontCourier8
  2100.     set win [winfo parent $c]
  2101.     set rtosx rtosx$win ; set rtosy rtosy$win
  2102.     set it [$c create line [$rtosx [expr {$x +$dx}]] [$rtosy [expr {$y +$dy}]] [$rtosx [expr {$x +$ex}]] [$rtosy [expr {$y +$ey}]] -fill $axisGray -tags $tags]
  2103.     $c lower $it
  2104.     
  2105.     if { "$n" != "" } {
  2106.    if { $ey > 0 } { set anch s
  2107.     } elseif { $ex > 0 } {set anch w 
  2108.     } elseif { $ex < 0 } {set anch e
  2109.     } elseif { $ey < 0 } {set anch n}
  2110.     
  2111.     $c create text  [$rtosx [expr {$x +1.5*$ex}]] [$rtosy [expr {$y +1.5*$ey}]] \
  2112.         -text [format "%.8g" $n] -font $fontCourier8 -tags $tags \
  2113.         -anchor $anch
  2114. }   }
  2115.  
  2116. proc doConfig { win }  {
  2117.     makeLocal $win c buttonFont
  2118.     $c delete configoptions
  2119.     set canv $c
  2120.    # set w $c.config
  2121.      set w $win.config
  2122.     catch {destroy $w}
  2123.     frame $w -borderwidth 2 -relief raised
  2124.  
  2125.     label $w.msg  -wraplength 600 -justify left -text "Plot Setup" -font $buttonFont
  2126.     pack $w
  2127.     pack $w.msg -side top
  2128.     set wb1 $w.choose1
  2129.     frame $wb1
  2130.     set wb2 $w.choose2
  2131.     frame $wb2
  2132.     pack $wb1 $wb2 -side left -fill x -pady 2m
  2133.     set item [$canv create window [$canv canvasx 10] [$canv canvasy  10] -window $w -anchor nw -tags configoptions]
  2134.     button $wb1.dismiss -command  "$canv delete $item; destroy $w " -text "ok" -font $buttonFont
  2135.     button $wb1.printoptions -text "Print Options" -command "mkPrintDialog .dial -canvas $c -buttonfont $buttonFont " -font $buttonFont
  2136.  
  2137.     pack $wb1.dismiss  $wb1.printoptions -side top 
  2138.     return "$wb1 $wb2"
  2139. }
  2140. # mkentry { newframe textvar text } 
  2141.  
  2142. set show_balloons 1
  2143.  
  2144. proc balloonhelp { win subwin msg } {
  2145.     global show_balloons
  2146.     if { $show_balloons == 0 } return;
  2147.     linkLocal  [oget $win c] helpPending
  2148.     if { [info exists helpPending] } {after cancel $helpPending}
  2149.     set helpPending [after 1000 [list balloonhelp1 $win $subwin $msg]]
  2150. }
  2151.  
  2152. proc balloonhelp1 { win subwin msg } {
  2153.     if { ![winfo exists $win] } { return }
  2154.     makeLocal $win c buttonFont
  2155.     set x0 [winfo rootx $win]
  2156.     set y0 [winfo rooty $win]
  2157.     
  2158.     
  2159.     set atx [expr {[winfo rootx $subwin] + [winfo width $subwin] - $x0} ]
  2160.     set aty [expr {[winfo rooty $subwin] + [winfo height $subwin] - $y0} ]
  2161.  
  2162.     set wid [$c cget -width]
  2163.     set wid2 [expr {round ($wid /2.0)}]
  2164.     set wid10 [expr {round ($wid /10.0)}]
  2165.  
  2166.     if { $aty <=1 } { set aty 30 } 
  2167.     incr aty 10
  2168.     incr atx 10
  2169.     set atx [$c canvasx $atx]
  2170.     set aty [$c canvasy $aty]
  2171.     #puts "$atx $aty"
  2172.     $c delete balloon
  2173.     $c create text $atx $aty -anchor nw -text $msg -font $buttonFont -width $wid2 -fill white -fill black -tags "balloon btext"
  2174.     desetq "x1 y1 x2 y2" [$c bbox btext]
  2175.  
  2176.     set x1 [expr {$x1 - .3*($x2-$x1)}]
  2177.     set x2 [expr {$x2 + .3*($x2-$x1)}]
  2178.     
  2179.     set y1 [expr {$y1 - .3*($y2-$y1)}]
  2180.     set y2 [expr {$y2 + .3*($y2-$y1)}]
  2181.  
  2182.     eval $c create polygon $x1 $y1  $x2 $y1 $x2 $y2 $x1 $y2  -fill beige -tags balloon -smooth 1
  2183.     $c raise btext
  2184.     
  2185. }
  2186.  
  2187. proc setBalloonhelp { win subwin msg } {
  2188.     makeLocal $win c
  2189.     bind $subwin <Enter> "balloonhelp $win $subwin [list $msg]"
  2190.     bind $subwin <Leave> "deleteBalloon $c"
  2191. }
  2192.     
  2193. proc deleteBalloon { c } {
  2194.     linkLocal $c helpPending
  2195.     if { [info exists helpPending] } {
  2196.     after cancel $helpPending
  2197.     unset helpPending
  2198.     }
  2199.     $c delete balloon
  2200. }
  2201.  
  2202.  
  2203. #
  2204.  #-----------------------------------------------------------------
  2205.  #
  2206.  # minMax --  Compute the max and min of the arguments, which may
  2207.  # be vectors or numbers
  2208.  #
  2209.  #  Results: list of MIN and MAX
  2210.  #
  2211.  #  Side Effects: none
  2212.  #
  2213.  #----------------------------------------------------------------
  2214. #
  2215. proc minMax { args } {
  2216.     set max [lindex [lindex $args 0] 0] ; set min $max ;
  2217.     foreach vec $args {
  2218.     foreach v $vec {
  2219.         if { $v > $max } {set max $v }
  2220.         if { $v < $min} {set min $v }
  2221.     }
  2222.     }
  2223.     return [list $min $max]
  2224. }
  2225.  
  2226. proc matrixMinMax { list } {
  2227. # compute the min max of the list    
  2228.     set min +10e300
  2229.     set max -10e300
  2230.     foreach mat $list {
  2231.     foreach row $mat {
  2232.         foreach v [ldelete nam $row] {
  2233.         if { $v > $max } {catch  { set max [expr {$v + 0}] }}
  2234.         if { $v < $min} {catch  { set min [expr {$v + 0}] }}
  2235.         }
  2236.         }
  2237.     }
  2238.     list $min $max
  2239. }
  2240.     
  2241. proc omPlotAny { data args } {
  2242.     # puts "data=<[lindex $data 0]>"
  2243.     set command [list [lindex [lindex $data 0] 0]  -data [lindex $data 0] ]
  2244.     if { "[lindex $command 0]" == "plot2d" } {
  2245.     lappend command -xfun {}
  2246.     }
  2247.     foreach v $args { [lappend command $v] }
  2248.     eval $command
  2249.     #eval [lindex [lindex $data 0] 0] -xfun [list {}] -data [list [lindex $data 0]] $args
  2250. }
  2251.  
  2252.  
  2253. proc resizeSubPlotWindows { win wid height } {
  2254.     set at [$win yview "@0,0"]
  2255.     foreach w [winfo children $win] {
  2256.     if { [string match plot* [lindex [split $w .] end]] } {
  2257.         resizePlotWindow $w [winfo width $w] $height
  2258.     }
  2259.   }
  2260.   if { "$at" != "" } { $win yview $at} 
  2261.  }
  2262.  
  2263.  
  2264.         
  2265. proc resizePlotWindow  { w width height } {
  2266.     if { [winfo width $w.c] <= 1 } {
  2267.     after 100 update ;
  2268.     return }
  2269.     if { ![catch { set tem [oget $w lastResize] } ] && [expr {[clock seconds] - $tem }] < 2 } { return
  2270. } else { oset $w lastResize [clock seconds ]
  2271.     }
  2272.     #puts "resizePlotWindow $w $width $height"
  2273.     
  2274.    # return
  2275.    set par [winfo parent $w]
  2276.    set facx 1.0
  2277.    set facy 1.0    
  2278.     set wid [winfo width $par]
  2279.     set hei [winfo height $par]
  2280.     
  2281.    if { "[winfo class $par]" == "Text" } {
  2282.    set dif 10
  2283.  
  2284.    set wid1 $wid ; set hei1 $hei
  2285.    #puts "now w=$w"
  2286.    #set wid1 [getPercentDim [oget $w widthDesired] width $par]        
  2287.    catch {set wid1 [getPercentDim [oget $w widthDesired] width $par] }
  2288.    catch {set hei1 [getPercentDim [oget $w heightDesired] height $par] }
  2289.    set wid [expr {($wid1 > $wid - 30 ? $wid - 30 : $wid1 )}]
  2290.    set hei [expr {($hei1 > $hei - 30 ? $hei - 30 : $hei1 )}]
  2291.    } else {
  2292.        set dif 10
  2293.  
  2294.    }
  2295.    
  2296.  
  2297.     #puts "width arg=$width,width $w=[winfo width $w],wid of $par=$wid,height=$height,hei=$hei,\[winfo width \$w.c\]=[winfo width $w.c]"
  2298. #     if { $width > $wid -20 || $wid > $width -20 }
  2299.     if { (abs($width-$wid) > $dif ||  abs($height-$hei) > $dif)
  2300. &&  [winfo width $w.c] > 1 } {
  2301.     set eps [expr {2 * [$w.c cget -insertborderwidth] + [$w.c cget -borderwidth] }]
  2302.     set epsx $eps
  2303.     set epsy $eps
  2304.     #puts "reconfiguring: w=$w,par=$par,dif=$dif,widths=$wid, \
  2305.     $width,[winfo width $par],[winfo width $w],[winfo width $w.c]\
  2306.     heights=$hei,$height,[winfo height $par],[winfo height $w],\
  2307.     [winfo height $w.c]"
  2308.     
  2309.     set extrawidth [expr {([winfo width $w] - [winfo width  $w.c]) +$epsx}]
  2310.     set extraheight [expr {([winfo height $w] - [winfo height  $w.c]) +$epsy}]
  2311.     set nwidth [expr {$wid - ($extrawidth > 0  ? $extrawidth : 0)}]
  2312.     set nheight [expr {$hei - ($extraheight > 0  ? $extraheight : 0)}]
  2313.     
  2314.     #puts "$w.c config -width $nwidth  -height $nheight, extraheight=$extraheight,epsy=$epsy"
  2315.     $w.c config -width $nwidth  -height $nheight
  2316.  
  2317.         }
  2318.             
  2319.  }
  2320.  
  2321.  
  2322.  
  2323. proc bboxToRadius { win  } {
  2324.     makeLocal $win bbox
  2325.     if { "$bbox" != "" } {
  2326.     linkLocal $win       xradius yradius xcenter ycenter
  2327.     set i 0
  2328.     foreach v { x y z } {
  2329.  
  2330.         set min [lindex $bbox $i]
  2331.         set max [lindex $bbox [expr $i +2]]
  2332.         if { "$min" != "" } {
  2333.         if { $min >= $max } {error "bad bbox $bbox since $min >= $max"}
  2334.         set ${v}radius [expr { ($max - $min) /2.0}]
  2335.         set ${v}center [expr { ($max + $min) /2.0}]
  2336.         }
  2337.     }
  2338.     }
  2339. }
  2340.  
  2341. proc updateParameters { win var value} {
  2342.     linkLocal $win parameters
  2343. #    puts "$win $var $value"
  2344.     set ans ""
  2345.     set comma ""
  2346.     
  2347.     foreach {v val} [splitParams $parameters] {
  2348.         if { "$v" == "$var" } {
  2349.         set val $value
  2350.     }
  2351.     append ans $comma $v=$val
  2352.     set comma ","
  2353.     }
  2354. #    puts "parameters=$ans"
  2355.     set parameters $ans
  2356. }
  2357.  
  2358. proc addSliders { win } {
  2359.     linkLocal $win sliders c width parameters
  2360.     set i 0
  2361.     if { "$sliders" == "" } { return }
  2362.     catch { destroy $c.sliders }
  2363.     set bg "#22aaee"
  2364.     set trough "#22ccff"
  2365.     frame $c.sliders -relief raised -highlightthickness 2 -highlightbackground $trough
  2366.     foreach v [split $sliders ,] {
  2367.     if { [regexp {([a-zA-Z0-9]+)[ ]*=?(([---0-9.]+):([---0-9.]+))?} $v  junk var junk x0 x1] } {
  2368.         incr i
  2369.         if { "$x0" == "" } { set x0 -5  ; set x1 5}
  2370.  
  2371.         set fr $c.sliders.fr$i
  2372.         frame $fr -background $bg 
  2373.         label $fr.lab -text $var: -background $bg 
  2374.         label $fr.labvalue -textvariable [oloc $win slidevalue$i]  -background $bg -relief sunken -justify left
  2375.         scale $fr.scale -command "sliderUpdate $win $var" \
  2376.             -from "$x0" -to $x1 -orient horizontal \
  2377.         -resolution [expr ($x1 - $x0) < 1 ? ($x1-$x0)/100.0 : .01] \
  2378.         -length [expr {$width/2}] -showvalue 0 -variable [oloc $win slidevalue$i] -background $bg -troughcolor "#22ccff" -highlightthickness 0
  2379.         pack $fr.lab -side left -expand 1 -fill x
  2380.         pack $fr.labvalue $fr.scale -side left
  2381.         pack  $fr -side top -expand 1 -fill x
  2382.         set found 0
  2383.         set val  [assoc $var [splitParams $parameters] no]
  2384.         if { "$val" == "no" } {
  2385.         set val  [expr ($x1 + $x0)/2.0]
  2386.         if { "$parameters" != "" }  { append parameters , } 
  2387.         append parameters $var=$val
  2388.         }
  2389.         $fr.scale set $val
  2390.     }
  2391.     }
  2392.  
  2393.     place  $c.sliders -in $c -x 4 -rely 1.0 -y -4 -anchor sw
  2394.  
  2395.     }
  2396.     
  2397.  
  2398. proc sliderUpdate { win var val } {
  2399.     linkLocal $win sliderCommand parameters
  2400.     set params $parameters
  2401.     updateParameters $win $var $val
  2402.     if { "$params" != "$parameters" &&
  2403.     [info exists sliderCommand] } {
  2404.  
  2405.     $sliderCommand $win $var $val
  2406. }   }
  2407.     
  2408.  
  2409.  
  2410.  
  2411. ## endsource plotconf.tcl
  2412. ## source plotdf.tcl
  2413.  
  2414. ###### plotdf.tcl ######
  2415. #######################################################################
  2416. #######  Copyright William F. Schelter.  All rights reserved.  ########
  2417. #######################################################################
  2418.  
  2419. set plotdfOptions {
  2420.     {dxdt "x-y^2+sin(x)*.3" {specifies dx/dt = dxdt.  eg -dxdt "x+y+sin(x)^2"} }
  2421.     {dydt "x+y" {specifies dy/dt = dydt.  eg -dydt "x-y^2+exp(x)"} }
  2422.     {dydx "" { may specify dy/dx = x^2+y,instead of dy/dt = x^2+y and dx/dt=1 }}
  2423.     {adamsMoulton red "Color to do adams moulton integration in. None means dont do" }
  2424.     {rungeKuttaA "" "Color to do Runge Kutta adaptive integration in. None means dont do" }
  2425.     
  2426.     {xradius 10 "Width in x direction of the x values" }
  2427.     {yradius 10 "Height in y direction of the y values"}
  2428.     {width 500 "Width of canvas in pixels"}
  2429.     {height 500 "Height of canvas in pixels" }
  2430.     {scrollregion {} "Area to show if canvas is larger" }
  2431.     {xcenter 0.0 {(xcenter,ycenter) is the origin of the window}}
  2432.     {ycenter 0.0 "see xcenter"}
  2433.     {bbox "" "xmin ymin xmax ymax .. overrides the -xcenter etc"}
  2434.     {tinitial 0.0 "The initial value of variable t"}
  2435.     {nsteps 100 "Number of steps to do in one pass"}
  2436.     {xfun "" "A semi colon separated list of functions to plot as well"}
  2437.     {tstep "" "t step size"}
  2438.     {direction "both" "May be both, forward or backward" }
  2439.     {versus_t 0 "Plot in a separate window x and y versus t, after each trajectory" }
  2440.     {windowname ".dfplot" "window name"}
  2441.     {parameters "" "List of parameters and values eg k=3,l=7+k"}
  2442.     {sliders "" "List of parameters ranges k=3:5,u"}
  2443.     {linecolors { green black  brown gray black} "colors to use for lines in data plots"}
  2444.     {doTrajectoryAt "" "Place to calculate trajectory"}
  2445.     {linewidth "1.0" "Width of integral lines" }
  2446.     {nolines 0 "If not 0, plot points and nolines"}
  2447.     {bargraph 0 "If not 0 this is the width of the bars on a bar graph" }
  2448.     {plotpoints 0 "if not 0 plot the points at pointsize" }
  2449.     {pointsize 2 "radius in pixels of points" }
  2450.     {autoscale "x y" "Set {x,y}center and {x,y}range depending on data and function. "}
  2451.     {zoomfactor "1.6 1.6" "Factor to zoom the x and y axis when zooming.  Zoom out will be reciprocal" }
  2452.     {errorbar 0 "If not 0 width in pixels of errorbar.  Two y values supplied for each x: {y1low y1high y2low y2high  .. }"}
  2453.      {data "" "List of data sets to be plotted.  Has form { {xversusy {x1 x2 ... xn} {y1 .. yn ... ym}} .. {againstIndex {y1 y2 .. yn}}  .. }"}
  2454.     {labelposition "10 35" "Position for the curve labels nw corner"}
  2455. }
  2456.  
  2457. if { "[info proc makeFrame]" == "" } { source "plotconf.tcl" }
  2458.  
  2459.  
  2460.  
  2461.  
  2462.  proc makeFrameDf { win } {
  2463.    set w [makeFrame $win df]
  2464.     makeLocal $win c dydx
  2465.  
  2466.     set top $win
  2467.    # puts "w=$w,win=$win"
  2468.     catch { set top [winfo parent $win]}
  2469.     catch {
  2470.  
  2471.     wm title $top "Direction Fields"
  2472.     wm iconname $top "DF plot"
  2473. #    wm geometry $top 750x700-0+20
  2474.    }
  2475.     set wb $w.buttons
  2476.    makeLocal $win buttonFont 
  2477.    label $w.msg  -wraplength 600 -justify left -text "A direction field plotter by William Schelter" -font $buttonFont
  2478.    
  2479.   button $wb.integrate -text "Integrate" -command "setForIntegrate $w" -font $buttonFont
  2480.    setBalloonhelp $win $wb.integrate {Causes clicking on the  plot with the left mouse button at a point, to draw a trajectory passing through that point.   Under Config there is an entry box which allows entering exact x,y coordinates, and which also records the place of the last trajectory computed.}
  2481.  
  2482.   button $wb.plotversust -text "Plot Versus t" -command "plotVersusT $w" -font $buttonFont
  2483.    setBalloonhelp $win $wb.plotversust {Plot the x and y values for the  last trajectory versus t.}   
  2484.    
  2485.    
  2486.   setForIntegrate $w
  2487.   pack $wb.integrate -side top -expand 1 -fill x
  2488.   pack $wb.plotversust -side top -expand 1 -fill x
  2489.  # pack $w.msg -side top
  2490.   pack $w
  2491.   return $win
  2492. }
  2493.  
  2494. proc swapChoose {win msg winchoose } {
  2495.    # global dydx dxdt dydt
  2496.     
  2497.     if { "$msg" == "dydt" } {
  2498.     pack $winchoose.dxdt -before $winchoose.dydt -side bottom
  2499.     oset $win dydx ""
  2500.     $winchoose.dydt.lab config -text "dy/dt"
  2501.     } else {
  2502.     pack forget $winchoose.dxdt
  2503.     oset $win dxdt 1
  2504.     oset $win dydx " "
  2505.     $winchoose.dydt.lab config -text "dy/dx"
  2506.     }
  2507. }
  2508.     
  2509.  
  2510. proc doHelpdf { win } {
  2511.     global Parser
  2512.  doHelp $win [join [list \
  2513. {
  2514. William Schelter's solver/plotter for ode systems.
  2515.  
  2516. To QUIT this HELP click here.
  2517.  
  2518. Clicking at a point computes the trajectory
  2519. (x(t),y(t)) starting at that point, and satisfying
  2520. the differential equation
  2521.     
  2522.   dx/dt = dxdt
  2523.   dy/dt = dydt
  2524.  
  2525. By clicking on Zoom, the mouse now allows you to zoom
  2526. in on a region of the plot.  Each click near a point
  2527. magnifies the plot, keeping the center at the point
  2528. you clicked.  Depressing the SHIFT key while clicking
  2529. zooms in the opposite direction.
  2530.  
  2531. To resume computing trajectories click on Integrate.
  2532.  
  2533. To change the differential equation, click on Config and
  2534. enter new values in the entry windows, and then click on
  2535. Replot in the main menu bar.
  2536.  
  2537. Holding the right mouse button down allows you to drag
  2538. (translate) the plot sideways or up and down.
  2539.  
  2540. Additional parameters such as the number of steps (nsteps),
  2541. the initial t value (tinitial), and the x and y centers
  2542. and radii, may be set under the  Config menu.
  2543.  
  2544. You may print to a postscript printer, or save the plot \
  2545. as a postscript file, by clicking on save.   To change \
  2546. between printing and saving see the Print Options under Config.
  2547.     
  2548. } $Parser(help)]]
  2549. }
  2550.  
  2551. proc setForIntegrate { win} {
  2552.     makeLocal $win c
  2553.     $c delete printrectangle
  2554.     bind $c  <1> "doIntegrateScreen $win %x %y "
  2555. }
  2556.  
  2557. ## source rk.tcl
  2558.  
  2559. ###### rk.tcl ######
  2560. #######################################################################
  2561. #######  Copyright William F. Schelter.  All rights reserved.  ########
  2562. #######################################################################
  2563.  
  2564. #proc try { } {
  2565.     #  proc ff { a b c } { return [expr {$b + $c}] }
  2566.     #  proc gg { a b c } { return [expr {$b - $c}] }
  2567. #  rungeKutta ff gg 0.2 0.2 0 .01 10
  2568. #}
  2569.  
  2570. proc rungeKutta { f g t0 x0 y0  h nsteps } {
  2571.   set n $nsteps
  2572.   set ans "$x0 $y0"
  2573.   set xn $x0
  2574.   set yn $y0
  2575.   set tn $t0
  2576.     set h2 [expr {$h / 2.0 }]
  2577.     set h6 [expr {$h / 6.0 }]
  2578.  catch {
  2579.   while { [incr nsteps -1] >= 0 } {
  2580.   
  2581.  
  2582.   set kn1 [$f $tn $xn $yn]
  2583.   set ln1 [$g $tn $xn $yn]
  2584.  
  2585.       set arg [list [expr {$tn + $h2}] [expr {$xn + $h2 * $kn1}] [expr {$yn + $h2*$ln1}]]
  2586.   set kn2 [eval $f $arg]
  2587.   set ln2 [eval $g $arg]
  2588.  
  2589.       set arg [list [expr {$tn + $h2}] [expr {$xn + $h2 * $kn2}] [expr {$yn +$h2*$ln2}]]
  2590.   set kn3 [eval $f $arg]
  2591.   set ln3 [eval $g $arg]
  2592.  
  2593.       set arg [list [expr {$tn + $h}] [expr {$xn + $h * $kn3}] [expr {$yn + $h*$ln3}]]
  2594.   set kn4 [eval $f $arg]
  2595.   set ln4 [eval $g $arg]
  2596.  
  2597.       set xn [expr {$xn + $h6 * ($kn1+2*$kn2+2*$kn3+$kn4)}]
  2598.       set yn [expr {$yn + $h6 * ($ln1+2*$ln2+2*$ln3+$ln4)}]
  2599.       set tn [expr {$tn+ $h}]
  2600.  
  2601.   lappend ans  $xn $yn
  2602.   }
  2603.  }
  2604.  
  2605.  return $ans 
  2606. }
  2607.  
  2608. proc pathLength { list } {
  2609.   set sum 0
  2610.   foreach { x y } $list {
  2611.       set sum [expr {$sum + sqrt($x*$x+$y*$y)}]
  2612.  }
  2613.   return $sum
  2614. }
  2615. proc rungeKuttaA { f g t0 x0 y0  h nsteps } {
  2616.   set ans [rungeKutta $f $g $t0 $x0 $y0 $h $nsteps]
  2617.   set count 0
  2618.   # puts "retrying([llength $ans]) .."
  2619.   while { [llength $ans] < $nsteps * .5  && $count < 7 } {
  2620.        incr count
  2621.        #set leng [pathLength $ans]
  2622.        #if { $leng == 0 } {set leng .001}
  2623.        set th [expr {$h / 3.0}]
  2624.        if { $th  < $h }  { set h $th }
  2625.        set ans  [rungeKutta $f $g $t0 $x0 $y0 $h $nsteps]
  2626.       # puts -nonewline "..(h=[format "%.5f" $h],pts=[llength $ans])"
  2627.        # flush stdout
  2628.   }
  2629.   return $ans
  2630. }
  2631.  
  2632.   
  2633.  
  2634. ## endsource rk.tcl
  2635. ## source adams.tcl
  2636.  
  2637. ###### adams.tcl ######
  2638.  
  2639.  
  2640. proc adamsMoulton { f g t0 x0 y0  h nsteps } {
  2641.     set ans [rungeKutta $f $g $t0 $x0 $y0 $h 3]
  2642.     catch { 
  2643.     set i 0
  2644.     set h24 [expr {$h /24.0}]
  2645.     foreach { x y } $ans {
  2646.     lappend listXff [xff  [expr {$t0 + $i * $h} ] $x $y]
  2647.     lappend listYff [yff  [expr {$t0 + $i * $h} ] $x $y]
  2648.     incr i
  2649.     set xn $x
  2650.     set yn $y
  2651.     }
  2652.  
  2653.     set n [expr $nsteps -3]
  2654.  
  2655.     while { [incr n -1] >= 0 } {
  2656.  
  2657.     #puts "listXff = $listXff"
  2658.     #puts "listYff = $listYff"        
  2659.     # adams - bashford formula:
  2660.     set xp [expr {$xn + ($h24)*(55 *[lindex $listXff 3]-59*[lindex $listXff 2]+37*[lindex $listXff 1]-9*[lindex $listXff 0]) }]
  2661.     set yp [expr {$yn + ($h24)*(55 *[lindex $listYff 3]-59*[lindex $listYff 2]+37*[lindex $listYff 1]-9*[lindex $listYff 0]) }]
  2662.     #puts "i=$i,xp=$xp,yp=$yp"
  2663.     # adams-moulton corrector-predictor:
  2664.     # compute the yp = yn+1 value..
  2665.     set t [expr {$t0 + $i * $h}]
  2666.     incr i
  2667.     if { 1 } {
  2668.     set xap [expr { $xn+($h24)*(9*[xff $t $xp $yp]+19*[lindex $listXff 3]-5*[lindex $listXff 2]+[lindex $listXff 1]) }]
  2669.     set yap [expr { $yn+($h24)*(9*[yff $t $xp $yp]+19*[lindex $listYff 3]-5*[lindex $listYff 2]+[lindex $listYff 1]) }]
  2670.  
  2671.     set xn $xap
  2672.     set yn $yap
  2673.    # puts "after correct:i=[expr $i -1],xn=$xn,yn=$yn"    
  2674.     # could repeat it, or check against previous to see if changes too much.
  2675.     }
  2676.     set listXff [lrange $listXff 1 end]
  2677.     set listYff [lrange $listYff 1 end]
  2678.  
  2679.     lappend listXff [xff $t $xn $yn]
  2680.     lappend listYff [yff $t $xn $yn]
  2681.  
  2682.     lappend ans $xn $yn
  2683.    # puts "ans=$ans"    
  2684.     }
  2685.     #puts "adams:t=$t"
  2686.   }
  2687.     return $ans
  2688. }
  2689.  
  2690. ## endsource adams.tcl
  2691.  
  2692. # sample procedures
  2693. # proc xff { t x y } { return [expr {$x + $y }] }
  2694. # proc yff { t x y } { return [expr {$x - $y }] }
  2695.  
  2696. proc doIntegrateScreen { win sx sy  } {
  2697.     makeLocal $win c
  2698.     doIntegrate $win [storx$win [$c canvasx $sx]] [story$win [$c canvasy $sy]]
  2699. }
  2700.  
  2701. proc doIntegrate { win x0 y0 } {
  2702.     # global xradius yradius c tstep  nsteps
  2703. #    puts "dointegrate $win $x0 $y0"
  2704.     makeLocal $win xradius yradius c tstep  nsteps direction linewidth tinitial versus_t linecolors
  2705.     linkLocal $win didLast trajectoryStarts
  2706.     set rtosx rtosx$win ; set rtosy rtosy$win      
  2707.     oset $win doTrajectoryAt [format "%.10g  %.10g" $x0 $y0]
  2708.     lappend trajectoryStarts [list $x0 $y0]
  2709.     
  2710.     set didLast {}
  2711.     # puts "doing at $doTrajectoryAt"
  2712.     set steps $nsteps
  2713.     if { "$tstep" == "" } {  
  2714.     set h [expr {[vectorlength $xradius $yradius] / 200.0}]
  2715.     set tstep $h
  2716.     } else {set h $tstep }
  2717.     
  2718.     # puts h=$h
  2719.     set todo $h
  2720.     switch $direction {
  2721.     forward { set todo "$h" }
  2722.     backward { set todo "[expr {- $h}]" }
  2723.     both { set todo "$h [expr {- $h}]" }
  2724.     }
  2725.     foreach method { adamsMoulton rungeKuttaA  } {
  2726.     set color [oget $win $method]
  2727.     if { "$color" != "" } {
  2728.         lappend methods $method
  2729.         lappend useColors $method $color
  2730.     }
  2731.     }
  2732.     set methodNo -1
  2733.     foreach method $methods {
  2734.     incr methodNo
  2735. #    puts method=$method
  2736.     foreach h $todo {
  2737.     set form [list $method xff yff $tinitial $x0 $y0 $h $steps]
  2738.     set ans [eval $form]
  2739.     lappend didLast $form
  2740.  
  2741.     #puts "doing: $form"
  2742.     set i -1
  2743.     set xn1 [$rtosx [lindex $ans [incr i]]]
  2744.     set yn1 [$rtosy [lindex $ans [incr i]]]
  2745.     set lim [expr {$steps * 2}]
  2746.     set mee [expr {pow(10.0,9)}]
  2747.     set ptColor [assoc $method $useColors ]
  2748.     set linecolor [lindex $linecolors $methodNo]
  2749.     #set im [getPoint 2 green]
  2750.     #set im1 [getPoint 2 purple]
  2751.     set im [getPoint 2 $ptColor]
  2752.     #set im1 [getPoint 2 purple]        
  2753.     catch  { 
  2754.         while { $i <= $lim } {
  2755.         set xn2  [$rtosx [lindex $ans [incr i]]]
  2756.         set yn2  [$rtosy [lindex $ans [incr i]]]
  2757.         # puts "$xn1 $yn1"
  2758.         # xxxxxxxx following is for a bug in win95 version
  2759.         if { abs($xn1) + abs($yn1) +abs($xn2)+abs($yn2) < $mee    } {
  2760.             $c create line $xn1 $yn1 $xn2 $yn2 -tags path -width $linewidth -fill $linecolor
  2761.             
  2762.         }
  2763.         
  2764.                 if { "$im" != "" } {
  2765.             #puts hi
  2766.             $c create image $xn1 $yn1 -image $im -anchor center \
  2767.                 -tags "point"
  2768.             
  2769.             } else {
  2770.             $c create oval [expr $xn1 -2] [expr $yn1 -2] [expr $xn1 +2] [expr $yn1 +2] -fill $color
  2771.  
  2772.         }
  2773.         
  2774.             
  2775.             
  2776.  
  2777.         # puts "$xn1 $yn1"
  2778.         set xn1 $xn2
  2779.         set yn1 $yn2
  2780.         }
  2781.     }   }
  2782.   }
  2783.   if { $versus_t } { plotVersusT $win}
  2784. }
  2785.  
  2786.  
  2787. proc plotVersusT {win } {
  2788.     linkLocal $win didLast dydt dxdt parameters xcenter xradius
  2789.     set nwin .versust.plot2d
  2790.     if { "$parameters" != ""  } { set pars ", $parameters"} else { set pars ""}
  2791.     oset $nwin themaintitle "dy/dt=$dydt, dx/dt=$dxdt $pars"
  2792.     lappend plotdata [list maintitle [list oget $nwin themaintitle]]
  2793.  
  2794.  
  2795.     foreach v $didLast {
  2796.     set ans [eval $v]
  2797.     desetq "tinitial x0 y0 h" [lrange $v 3 end]
  2798.     set this [lrange $v 0 5]
  2799.     if { [info exists doing($this) ] } { set tem $doing($this) } else {
  2800.         set tem ""
  2801.     }
  2802.     set doing($this) ""
  2803.     set allx "" ; set ally "" ; set allt ""
  2804.     set ii 0 
  2805.     foreach {x y } $ans {
  2806.         lappend allx $x
  2807.         lappend ally $y
  2808.         lappend allt [expr $tinitial + $h*$ii]
  2809.         incr ii
  2810.     }
  2811.     
  2812.     foreach u $tem v [list $allx $ally $allt] {
  2813.         if { $h > 0 } { lappend doing($this) [concat $u $v]} else {
  2814.             lappend doing($this) [concat [lreverse $v] $u]
  2815.         }   }
  2816.     }
  2817.  
  2818.     foreach {na val } [array get doing] {
  2819.     lappend plotdata [list label "x versus t"] [list plotpoints 2]
  2820.     lappend plotdata [list xversusy [lindex $val 2] [lindex $val 0] ]
  2821.     lappend plotdata [list label "y versus t"]    
  2822.     lappend plotdata [list xversusy [lindex $val 2] [lindex $val 1] ]
  2823.     }
  2824.     if { ![winfo exists .versust] } {
  2825.     toplevel .versust
  2826.     }
  2827.     
  2828.  
  2829.     plot2d -data $plotdata -windowname $nwin -ycenter $xcenter -yradius $xradius
  2830.     wm title .versust "X and Y versus t"
  2831. }
  2832.  
  2833. proc lreverse { lis } {
  2834.     set ans ""
  2835.     set i [llength $lis]
  2836.     while { [incr i -1]>=0 } {
  2837.     lappend ans [lindex $lis $i]
  2838.     }
  2839.     return $ans
  2840. }
  2841.  
  2842.  
  2843. #
  2844.  #-----------------------------------------------------------------
  2845.  #
  2846.  # $rtosx,$rtosy --  convert Real coordinate to screen coordinate
  2847.  #
  2848.  #  Results: a window coordinate
  2849.  #
  2850.  #  Side Effects: 
  2851.  #
  2852.  #----------------------------------------------------------------
  2853.  
  2854.  
  2855. #
  2856.  #-----------------------------------------------------------------
  2857.  #
  2858.  # $storx,$story --  Convert a screen coordinate to a Real coordinate.
  2859.  #
  2860.  #  Results:
  2861.  #
  2862.  #  Side Effects: 
  2863.  #
  2864.  #----------------------------------------------------------------
  2865. #
  2866.  
  2867. proc drawArrowScreen { c atx aty dfx dfy } {
  2868.  
  2869.     set x1 [expr {$atx + $dfx}]
  2870.     set y1 [expr {$aty + $dfy}]
  2871.     #   set x2 [expr {$atx + .8*$dfx +.1* $dfy}]
  2872.     #   set y2 [expr {$aty + .8*$dfy - .1* $dfx}]
  2873.     #   set x3 [expr {$atx + .8*$dfx -.1* $dfy}]
  2874.     #   set y3 [expr {$aty + .8*$dfy + .1* $dfx}]
  2875.   $c create line $atx $aty $x1 $y1 -tags arrow -fill blue -arrow last -arrowshape {3 5 2}
  2876. #  $c create line $x2 $y2  $x1 $y1 -tags arrow -fill red
  2877. #  $c create line $x3 $y3 $x1 $y1 -tags arrow -fill red
  2878. }
  2879.  
  2880. proc drawDF { win tinitial } {
  2881.     global  axisGray
  2882.     makeLocal  $win xmin xmax   xcenter ycenter c ymin ymax transform
  2883.  
  2884.     # flush stdout
  2885.     set rtosx rtosx$win ; set rtosy rtosy$win
  2886.     set storx   storx$win  ;   set story   story$win  
  2887.     set stepsize 30
  2888.     set min 100000000000.0
  2889.     set max 0.0
  2890.     set t0 $tinitial
  2891.     set xfactor [lindex $transform 0]
  2892.     set yfactor [lindex $transform 3]
  2893.     set extra $stepsize  
  2894.     set uptox [expr {[$rtosx $xmax] + $extra}]
  2895.     set uptoy [expr {[$rtosy $ymin] + $extra}]
  2896.     # draw the axes:
  2897.     #puts "draw [$rtosx $xmin] to $uptox"
  2898.     for { set x [expr {[$rtosx $xmin] - $extra}] } { $x < $uptox } { set x [expr {$x +$stepsize}] } {
  2899.     for { set y [expr {[$rtosy $ymax] - $extra}] } { $y < $uptoy } { set y [expr {$y + $stepsize}] } {
  2900.         set args "$t0 [$storx $x] [$story $y]"
  2901.         set dfx [expr {$xfactor * [eval xff $args]}]
  2902.         # screen y is negative of other y
  2903.         set dfy [expr  {$yfactor * [eval yff $args]}]
  2904.         #     puts "$dfx $dfy"
  2905.         set len  [vectorlength $dfx $dfy]
  2906.         append all " $len $dfx $dfy "
  2907.         if { $min > $len } { set min $len }
  2908.         if { $max < $len } {set  max $len}
  2909.     }   }
  2910.     set fac [expr {($stepsize -5 -8)/($max - $min)}]
  2911.     set arrowmin 8
  2912.     set arrowrange [expr {$stepsize -4 - $arrowmin}]
  2913.     set s1 [expr {($arrowrange*$min+$arrowmin*$min-$arrowmin*$max)/($min-$max)}]
  2914.     set s2 [expr {$arrowrange/($max-$min) }]
  2915.     # we calculate fac for each length, so that
  2916.     # when we multiply the vector times fac, its length
  2917.     # will fall somewhere in [arrowmin,arrowmin+arrowrange].
  2918.     # vectors of length min and max resp. should get mapped
  2919.     # to the two end points.
  2920.     # To do this we set fac [expr {$s1/$len + $s2}]
  2921.     # puts "now to draw,s1=$s1 s2=$s2,max=$max,min=$min"
  2922.     # puts "xfactor=$xfactor,yfactor=$yfactor"
  2923.  
  2924.     
  2925.     set i -1
  2926.     for { set x [expr {[$rtosx $xmin] - $stepsize}] } { $x < $uptox } { set x [expr {$x +$stepsize}] } {
  2927.     for { set y [expr {[$rtosy $ymax] - $stepsize}] } { $y < $uptoy } { set y [expr {$y + $stepsize}] } {
  2928.         
  2929.         
  2930.         set len [lindex $all [incr i]]
  2931.         
  2932.         set fac [expr {$s1/$len + $s2}]
  2933.         set dfx [lindex $all [incr i]]
  2934.         set dfy [lindex $all [incr i]]
  2935.         #puts "[$storx $x] [$story $y] x=$x y=$y dfx=$dfx dfy=$dfy fac=$fac"
  2936.         # puts "$len $dfx $dfy" 
  2937.         drawArrowScreen $c $x $y [expr {$fac * $dfx}] [expr {$fac * $dfy}]
  2938.         }
  2939.     }
  2940.     
  2941.     $c create line [$rtosx 0 ] [$rtosy -1000] [$rtosx 0] [$rtosy 1000] \
  2942.         -fill $axisGray
  2943.     $c create line [$rtosx -1000] [$rtosy 0] [$rtosx 1000] [$rtosy 0] \
  2944.         -fill $axisGray
  2945.     axisTicks $win $c
  2946. }
  2947.  
  2948. proc parseOdeArg {  s } {
  2949.     set orig $s
  2950.     set w "\[ ]*"
  2951.     set exp "\[dD]$w\\($w\(\[xyz])$w,$w\(\[xyt])$w\\)$w=(\[^;]+)"
  2952.     while { [regexp $exp $s junk x t expr ] } {
  2953.     lappend ans  -d${x}d$t
  2954.     lappend ans $expr
  2955.     regexp -indices $exp $s junk x t expr
  2956.     set s [string range $s [lindex $junk 1] end]
  2957.     }
  2958.     if { ![info exists ans] || ([llength $ans] == 2 && "[lindex $ans 0]" != "-dydx") } {
  2959.     error "bad -ode argument: $orig\nwant d(y,x)=f(x,y) \n   OR d(x,t)=f(x,y) d(y,t)=g(x,y) "
  2960.     }
  2961.     return $ans
  2962. }
  2963.  
  2964.  
  2965.  
  2966. proc plotdf { args } {
  2967.     global plotdfOptions   printOption printOptions plot2dOptions
  2968.     # puts "args=$args"
  2969.     # to see options add: -debug 1
  2970.     set win [assoc -windowname $args]
  2971.     if { "$win" == "" } {set win [getOptionDefault windowname $plotdfOptions] }
  2972.     if { "[lindex $args 0]" == "-ode" } {
  2973.     set tem [parseOdeArg [lindex $args 1]]
  2974.     set args [lrange $args 2 end]
  2975.     set args [concat $tem  $args]
  2976.     }
  2977.     global [oarray $win]
  2978.     getOptions $plotdfOptions $args -usearray [oarray $win]
  2979.  
  2980.     makeLocal $win dydx
  2981.  
  2982.     if { "$dydx" !="" } { oset $win dxdt 1 ; oset $win dydt $dydx }
  2983.     setPrintOptions $args
  2984.     foreach v {trajectoryStarts recompute} {
  2985.         catch { unset [oloc $win $v]  }
  2986.     }
  2987.     
  2988.     makeFrameDf $win
  2989.     oset $win sliderCommand sliderCommandDf
  2990.     oset $win trajectoryStarts ""
  2991.     
  2992.  
  2993.     oset $win maintitle [concat "makeLocal $win  dxdt dydt dydx ;"  \
  2994.         {if { "$dydx" == "" } { concat "dx/dt = $dxdt , dy/dt = $dydt"}  else {
  2995.     concat "dy/dx = $dydt" } } ]
  2996.     replotdf $win
  2997.     }
  2998.  
  2999. proc replotdf { win } {
  3000.     global plotdfOptions
  3001.     linkLocal $win xfundata data
  3002.     if { ![info exists data] } {
  3003.     set data ""
  3004.     
  3005.     }
  3006.     makeLocal $win c dxdt dydt tinitial nsteps xfun     doTrajectoryAt parameters 
  3007.  
  3008.     setUpTransforms $win 1.0
  3009.     setXffYff $dxdt $dydt $parameters
  3010.     $c delete all
  3011.     setForIntegrate $win
  3012.     oset $win curveNumber -1
  3013.     drawDF $win $tinitial
  3014.     if { "$doTrajectoryAt" != "" } {
  3015.          eval doIntegrate $win  $doTrajectoryAt
  3016.     }
  3017.     set xfundata ""
  3018.     foreach v [sparseListWithParams $xfun {x y t} $parameters ] {
  3019.     proc _xf {  x  } "return \[expr { $v } \]"
  3020.     regsub "\\$" $v "" label
  3021.     lappend xfundata [list label $label] \
  3022.       [linsert [calculatePlot $win _xf $nsteps]  \
  3023.         0 xversusy]
  3024.     }
  3025.     redraw2dData $win -tags path
  3026.     
  3027. }    
  3028.  
  3029. proc setXffYff { dxdt dydt parameters } {
  3030.     
  3031.     proc xff { t x y } "expr { [sparseWithParams $dxdt { x y} $parameters] }"    
  3032.     proc yff { t x y } "expr { [sparseWithParams $dydt { x y} $parameters] } "
  3033. }
  3034.  
  3035. proc doConfigdf { win } {
  3036.     desetq "wb1 wb2" [doConfig $win]
  3037.     makeLocal $win buttonFont 
  3038.     frame $wb1.choose1
  3039.     set frdydx $wb1.choose1
  3040.     button $frdydx.dydxbut -command "swapChoose $win dydx $frdydx " \
  3041.         -text "dy/dx" -font $buttonFont
  3042.     button $frdydx.dydtbut -command "swapChoose $win dydt $frdydx" \
  3043.         -text "dy/dt,dx/dt" -font $buttonFont
  3044.     mkentry $frdydx.dxdt [oloc $win dxdt] "dx/dt" $buttonFont
  3045.     mkentry $frdydx.dydt [oloc $win dydt] "dy/dt" $buttonFont
  3046.     pack $frdydx.dxdt  $frdydx.dydt -side bottom  -fill x -expand 1
  3047.     pack $frdydx.dydxbut $frdydx.dydtbut -side left -fill x -expand 1
  3048.     
  3049.     foreach w {versus_t parameters linewidth xradius yradius xcenter ycenter tinitial nsteps tstep direction xfun linecolors rungeKuttaA adamsMoulton } {
  3050.     mkentry $wb1.$w [oloc $win $w] $w $buttonFont
  3051.     pack $wb1.$w -side bottom -expand 1 -fill x
  3052.     }
  3053.     mkentry $wb1.doTrajectoryAt [oloc $win doTrajectoryAt] \
  3054.         "Trajectory at" $buttonFont
  3055.     bind $wb1.doTrajectoryAt.e <KeyPress-Return> \
  3056.         "eval doIntegrate $win \[oget $win doTrajectoryAt\] "
  3057.     pack  $wb1.doTrajectoryAt   $frdydx    -side bottom -expand 1 -fill x
  3058.     if { "[oget $win dydx]" != "" } { swapChoose $win dydx $frdydx }
  3059.     setForIntegrate $win
  3060.  }
  3061.  
  3062.  
  3063.  
  3064. proc sliderCommandDf { win var val } {
  3065.     linkLocal $win recompute
  3066.     updateParameters $win $var $val
  3067.     set com "recomputeDF $win"
  3068. # allow for fast move of slider...    
  3069.     after cancel $com
  3070.     after 50 $com
  3071. }
  3072.  
  3073. proc recomputeDF { win } {
  3074.     linkLocal $win  recompute 
  3075.     if { [info exists recompute]  } {
  3076.     incr recompute
  3077.     return
  3078.     } else {
  3079. #    puts "set recompute 1"
  3080.     set recompute 1
  3081.     }
  3082.     linkLocal $win trajectoryStarts  c tinitial dxdt dydt parameters
  3083.     set redo 0
  3084.     set trajs ""
  3085.  
  3086.     catch {     set trajs $trajectoryStarts} 
  3087.  
  3088.  
  3089.     while { $redo != $recompute } {
  3090. #    puts "    setXffYff $dxdt $dydt $parameters"
  3091.     setXffYff $dxdt $dydt $parameters
  3092. #    $c delete path point arrow
  3093.     $c delete all
  3094.     catch { unset  trajectoryStarts }
  3095.     set redo $recompute
  3096.     foreach pt $trajs {
  3097.         desetq "x0 y0" $pt
  3098.         catch { doIntegrate $win $x0 $y0 }
  3099.         update
  3100.         if { $redo != $recompute } { break }
  3101.     }
  3102.     if  { $redo == $recompute } {
  3103.         catch { drawDF $win $tinitial }
  3104.     }
  3105.     }
  3106. #    puts "    unset recompute"
  3107.     unset recompute
  3108. }
  3109.     
  3110.  
  3111.     
  3112.         
  3113.     
  3114.     
  3115.     
  3116.  
  3117. ## endsource plotdf.tcl
  3118. ## source plot2d.tcl
  3119.  
  3120. ###### plot2d.tcl ######
  3121. ############################################################
  3122. # Netmath       Copyright (C) 1998 William F. Schelter     #
  3123. # For distribution under GNU public License.  See COPYING. # 
  3124. ############################################################
  3125.  
  3126. set p .plot
  3127. catch { destroy $p }
  3128.  
  3129. set plot2dOptions { 
  3130.     {xradius 10 "Width in x direction of the x values" }
  3131.     {yradius 10 "Height in y direction of the y values"}
  3132.     {width 500 "Width of canvas in pixels"}
  3133.     {height 500 "Height of canvas in pixels" }
  3134.     {xcenter 0.0 {(xcenter,ycenter) is the origin of the window}}
  3135.     {xfun "" {function of x to plot eg: sin(x) or "sin(x);x^2+3" }}
  3136.     {parameters "" "List of parameters and values eg k=3,l=7+k"}
  3137.     {sliders "" "List of parameters ranges k=3:5,u"}
  3138.     {nsteps "100" "mininmum number of steps in x direction"}
  3139.     {ycenter 0.0 "see xcenter"}
  3140.     {bbox "" "xmin ymin xmax ymax .. overrides the -xcenter etc"}
  3141.     {screenwindow "20 20 700 700" "Part of canvas on screen"}
  3142.  
  3143.     {windowname ".plot2d" "window name"}
  3144.     {nolines 0 "If not 0, plot points and nolines"}
  3145.     {bargraph 0 "If not 0 this is the width of the bars on a bar graph" }
  3146.     {linewidth "0.6" "Width of plot lines" }
  3147.     {plotpoints 0 "if not 0 plot the points at pointsize" }
  3148.     {pointsize 2 "radius in pixels of points" }
  3149.     {linecolors {blue green red brown gray black} "colors to use for lines in data plots"}
  3150.     {labelposition "10 35" "Position for the curve labels nw corner"}
  3151.     {xaxislabel "" "Label for the x axis"}
  3152.     {yaxislabel "" "Label for the y axis"}
  3153.     {autoscale "y" "Set {x,y}center and {x,y}range depending on data and function. Value of y means autoscale in y direction, value of {x y} means scale in both.  Supplying data will automatically turn this on."}
  3154.     {zoomfactor "1.6 1.6" "Factor to zoom the x and y axis when zooming.  Zoom out will be reciprocal" }
  3155.     {errorbar 0 "If not 0 width in pixels of errorbar.  Two y values supplied for each x: {y1low y1high y2low y2high  .. }"} 
  3156.     {data "" "List of data sets to be plotted.  Has form { {xversusy {x1 x2 ... xn} {y1 .. yn ... ym}} .. {againstIndex {y1 y2 .. yn}}  .. }"}
  3157. }
  3158.  
  3159. proc argSuppliedp { x } {
  3160.   upvar 1 args a
  3161.   return [expr [set i [lsearch $a $x]] >= 0 && $i%2 == 0] 
  3162. }
  3163.     
  3164. proc mkPlot2d { args } {
  3165.     global plot2dOptions  printOption axisGray
  3166.     #puts "args=<$args>"
  3167.     # global  screenwindow c xmax xmin ymin ymax 
  3168.     # eval global [optionFirstItems $plot2dOptions]
  3169.     set win [assoc -windowname $args]
  3170.     if { "$win" == "" } {
  3171.     set win [getOptionDefault windowname $plot2dOptions] }
  3172.     global  [oarray $win]
  3173.     set data [assoc -data $args ]
  3174.     # puts ranges=[plot2dGetDataRange $data]
  3175.  
  3176.     getOptions $plot2dOptions $args -usearray [oarray $win]
  3177.     linkLocal $win autoscale 
  3178.     if { [argSuppliedp -data] && ![argSuppliedp -autoscale] &&
  3179.     ![argSuppliedp -xradius] } {
  3180.     lappend autoscale x
  3181.     }
  3182.     if { ![argSuppliedp -autoscale] & [argSuppliedp -yradius] } {
  3183.     set autoscale [ldelete y $autoscale]
  3184.     }    
  3185.     
  3186.     oset $win curveNumber -1
  3187.     setPrintOptions $args
  3188.     oset $win maintitle ""    
  3189.     setupCanvas $win 
  3190.     catch { destroy $windowname }
  3191.     
  3192.     makeFrame2d $win
  3193.     oset $win sliderCommand sliderCommandPlot2d
  3194.     makeLocal $win c
  3195.     return $win
  3196.     
  3197. }
  3198.  
  3199. proc  makeFrame2d  { win } {
  3200.     set w [makeFrame $win 2d]
  3201.     set top $w
  3202.     catch { set top [winfo parent $w]}
  3203.     catch {
  3204.     wm title $top "Schelter's 2d Plot Window"
  3205.     wm iconname $top "2d plot"
  3206.    # wm geometry $top 750x700-0+20
  3207.    }
  3208.     pack $w
  3209.    return $w
  3210.  
  3211. }
  3212.  
  3213. proc doConfig2d { win } {
  3214.     desetq "wb1 wb2" [doConfig $win]
  3215.     makeLocal $win buttonFont 
  3216.     mkentry $wb1.nsteps [oloc $win nsteps]  "Number of mesh grids"  $buttonFont
  3217.     mkentry $wb1.xfun [oloc $win xfun]  "y=f(x)"  $buttonFont
  3218.     bind $wb1.xfun.e <Return> "replot2d $win"
  3219.     # button .jim.buttons.rot "rotate" -command "bindForRotation"
  3220.     # pack .jim.buttons.rot
  3221.     pack $wb1.xfun  $wb1.nsteps -expand 1 -fill x
  3222.     foreach w {xradius yradius xcenter ycenter linecolors autoscale linewidth parameters} {
  3223.     mkentry $wb1.$w [oloc $win $w] $w $buttonFont
  3224.     pack $wb1.$w -side bottom -expand 1 -fill x
  3225.     }
  3226. }
  3227.  
  3228. proc doHelp2d {win } {
  3229.  global Parser
  3230.  
  3231. doHelp $win [join [list \
  3232. {
  3233.  
  3234. William Schelter's plotter for two dimensional graphics.
  3235.  
  3236. to QUIT this HELP click here.
  3237.  
  3238. By clicking on Zoom, the mouse now allows you to zoom \
  3239. in on a region of the plot.  Each click near a point \
  3240. magnifies the plot, keeping the center at the point \
  3241. you clicked.  Depressing the SHIFT key while clicking \
  3242. zooms in the opposite direction. 
  3243.  
  3244. To change the functions plotted, click on Config and \
  3245. enter new values in the entry windows, and then click on \
  3246. Replot in the main menu bar.
  3247.  
  3248. Holding the right mouse button down allows you to drag
  3249. (translate) the plot sideways or up and down.
  3250.  
  3251. Additional parameters such as the number of steps (nsteps), \
  3252. and the x and y centers and radii, may be set under the \
  3253. Config menu.
  3254.  
  3255. You may print to a postscript printer, or save the plot \
  3256. as a postscript file, by clicking on save.   To change \
  3257. between printing and saving see the Print Options under Config.
  3258.     
  3259.  
  3260.  
  3261.  
  3262.  
  3263. } $Parser(help)]]
  3264. }
  3265.  
  3266.  
  3267. set   plot(numberPlots) 4
  3268. proc mkExtraInfo { name args } {
  3269.     # global plot     
  3270.     catch { destroy $name }
  3271.  
  3272.     toplevel $name
  3273.     wm geometry $name -10+10
  3274.  # pack $name
  3275.     set canv [assoc -canvas $args ]
  3276.     set i 0
  3277.     set w $name
  3278.     frame $w.grid
  3279.     pack $w.grid -expand yes -fill both -padx 1 -pady 1
  3280.     grid $w.grid
  3281.     grid rowconfig    $w.grid 0 -weight 1 -minsize 0
  3282.     grid columnconfig $w.grid 0 -weight 2 -minsize 0
  3283.     
  3284.     set i 0
  3285.     label $w.title -text "Extra Plotting Information" -width 50
  3286.     grid $w.title -in $w.grid -columnspan 2 -row 0 -column 0
  3287.     incr i
  3288.     label $w.labppl -text "Plot Function f(x)"
  3289.     label $w.labcol -text "plot color"
  3290.     grid $w.labppl -padx 1 -in $w.grid  -pady 1 -row $i -column 0 -sticky news
  3291.     grid $w.labcol -padx 1 -in $w.grid  -pady 1 -row $i -column 1 -sticky news
  3292.     incr i
  3293.     set k 1
  3294.     proc mkPlotEntry { w k i } {
  3295.       entry $w.plot$k -textvariable plot(fun$k)
  3296.       entry $w.color$k -textvariable plot(col$k)
  3297.       grid $w.plot$k -padx 10 -in $w.grid  -pady 1 -row $i -column 0 -sticky news
  3298.       grid $w.color$k -padx 4 -in $w.grid  -pady 1 -row $i -column 1 -sticky news
  3299.     }
  3300.     while { $k <= $plot(numberPlots) } { mkPlotEntry $w $i $k ; incr i ; incr k}
  3301.    }
  3302.  
  3303. proc calculatePlot { win fun  nsteps } {
  3304.   #  global xmin xmax  ymax ymin
  3305.     makeLocal $win xmin xmax  ymax ymin
  3306.     set h0 [expr {($xmax - $xmin)/double($nsteps )}]
  3307.     set x0 $xmin
  3308.     set res ""
  3309.     set limit [expr {100 * (abs($ymax)> abs($ymin) ? abs($ymax) : abs($ymin))}]
  3310.     while { $x0 < $xmax } {
  3311.     set lastx0 $x0
  3312.     #puts xmax=$xmax
  3313.     append res " " [calculatePlot1 $win $x0 $h0 $fun $limit]
  3314.     #puts res:[lrange $res [expr [llength $res] -10] end]
  3315.     if { $x0 <= $lastx0 }    {
  3316.         # puts "x0=$x0,($lastx0)"
  3317.         set x0 [expr {$x0 + $h0/4}]
  3318.         #error "how is this?"
  3319.     }
  3320.     }
  3321.     # puts "plength=[llength $res]"
  3322.     return $res
  3323. }
  3324.  
  3325.  
  3326. #
  3327.  #-----------------------------------------------------------------
  3328.  #
  3329.  # calculatePlot1 --   must advance x0 in its caller
  3330.  #
  3331.  #  Results: one connected line segment as "x0 y0 x1 y1 x2 y2 .."
  3332.  #
  3333.  #  Side Effects: must advance x0 in its caller
  3334.  #
  3335.  #----------------------------------------------------------------
  3336. #
  3337. proc  calculatePlot1 { win x0 h0 fun  limit } {
  3338.      #puts "calc:$win $x0 $h0 $limit $fun"
  3339.     makeLocal $win xmax
  3340.     set ansx ""
  3341.     set ansy ""
  3342.    while { [catch { set y0 [$fun $x0] } ] && $x0 <= $xmax }  {
  3343.        set x0 [expr {$x0 + $h0}] }
  3344.     if { $x0 > $xmax } {
  3345.     # puts "catching {$fun $x0}"
  3346.     uplevel 1 set x0 $x0
  3347.     return ""
  3348.     }
  3349.     set ans "$x0 $y0"
  3350.     set delta 0
  3351.     set littleLimit [expr {$limit/50.0 }]
  3352.     set veryLittleLimit [expr {$littleLimit * 10}]
  3353.     # now have one point..
  3354.     # this is really set below for subsequent iterations.
  3355.     set count 10
  3356.     set heps [expr {$h0/pow(2,6)}]
  3357.     set h2 [expr {$h0 *2 }]
  3358.     set ii 0
  3359.     set x1 [expr {$x0 + $h0}]
  3360.     while { $x1 <= $xmax  && $ii < 5000 } {
  3361.         # puts $x1
  3362.         incr ii
  3363.     if { [catch { set y1 [$fun $x1] } ] } {
  3364.             #puts "catching1 {$fun $x1}"
  3365.         if { $count > 0 } {
  3366.         # try a shorter step.
  3367.         set x1 [expr {($x1 -$x0)/2 + $x0}]
  3368.         incr count -1
  3369.         continue
  3370.         } else {
  3371.         uplevel 1 set x0 [expr {$x0 + $heps}]
  3372.         return [list $ansx $ansy]
  3373.         }
  3374.     }
  3375.     # ok have x1,y1
  3376.     # do this on change in slope!! not change in limit..
  3377.  
  3378.     set nslope [expr {($y1-$y0)/($x1-$x0)}]
  3379.     catch { set delta [expr {($slope * $nslope < 0 ? abs($slope-$nslope) : .1*abs($slope-$nslope))}]} 
  3380.     # catch { set delta [expr {abs($slope - ($y1-$y0)/($x1-$x0))}] }
  3381.     
  3382.     if { $count > 0 && (abs($y1 - $y0) > $h2 || $delta > $h2)  && (0 || abs($y1) < $littleLimit)
  3383.             } {
  3384.             #puts "too  big $y1 [expr {abs($y1-$y0)}] at $x1"
  3385.             set x1 [expr {($x1 -$x0)/2 + $x0}]
  3386.         incr count -1
  3387.              continue 
  3388.              } elseif { abs($y1) > $limit || abs($y1-$y0) > $limit
  3389.             || $delta > $littleLimit } {
  3390.         incr ii
  3391.         if { $count == 0 } {
  3392.             uplevel 1 set x0 [expr {$x0 + $heps}]
  3393.             return [list $ansx $ansy]
  3394.         } else {
  3395.             
  3396.             set x1 [expr {($x1 -$x0)/2 + $x0}]
  3397.             incr count -1
  3398.             continue
  3399.         }
  3400.         } else {
  3401.          if {   abs($y1-$y0) > $limit/4} {
  3402.          
  3403.         # puts "x0=$x0,x1=$x1,y0=$y0,y1=$y1"
  3404.         uplevel 1 set x0 $x1
  3405.         return [list $ansx $ansy]
  3406.     }
  3407.  
  3408.     
  3409.         # hopefully common case!!
  3410.         # puts "got it: $x1,$y1,"
  3411.             lappend ansx $x1
  3412.             lappend ansy $y1
  3413.         #append ans " $x1 $y1"
  3414.                   set slope [expr {($y1-$y0)/($x1-$x0)} ]
  3415.         set x0 $x1
  3416.         set y0 $y1
  3417.     set x1 [expr {$x0 + $h0}]
  3418.         set count 4
  3419.         }
  3420.     }
  3421.     uplevel 1 set x0 $x1
  3422.     return [list $ansx $ansy]
  3423.     }
  3424.  
  3425.     
  3426.  
  3427.     
  3428.  
  3429. #proc setup_xf { vars form } {
  3430. #    set s [sparse $form ] 
  3431. #    proc _xf  $vars  "return \[ expr { $s } \]"
  3432. #}
  3433.  
  3434.  
  3435. #
  3436.  #-----------------------------------------------------------------
  3437.  #
  3438.  # nextColor --  get next COLOR and advance the curveNumber
  3439.  #
  3440.  #  Results: a color
  3441.  #
  3442.  #  Side Effects: the local variable for WIN called curveNumber is incremented
  3443.  #
  3444.  #----------------------------------------------------------------
  3445. #
  3446. proc nextColor { win } {
  3447.     makeLocal $win linecolors 
  3448.     if { [catch { set i [oget $win curveNumber] } ] } { set i -1 }
  3449.     set color [lindex $linecolors [expr {[incr i]%[llength $linecolors]}]]
  3450.     oset $win curveNumber $i
  3451.     return $color
  3452. }
  3453.     
  3454.  
  3455. proc plot2d {args } {
  3456.     #puts "args=$args"
  3457.     set win [apply mkPlot2d $args]
  3458.     replot2d $win
  3459.     return $win
  3460. }
  3461.  
  3462. proc replot2d {win } {
  3463.     global printOption axisGray plot2dOptions
  3464.     linkLocal $win xfundata data
  3465.     foreach v $data {
  3466.     if { "[assq [lindex $v 0] $plot2dOptions notthere]" != "notthere" } {
  3467.         oset $win [lindex $v 0] [lindex $v 1]
  3468.     }
  3469.     }
  3470.     linkLocal $win parameters 
  3471.     makeLocal $win xfun nsteps c linecolors xaxislabel yaxislabel  autoscale sliders
  3472.     if { "$sliders" != "" && ![winfo exists $c.sliders] } {
  3473.     addSliders $win
  3474.     }
  3475.     set xfundata ""
  3476. #   puts xfun=$xfun,parameters=$parameters,[oget $win xradius],[oget $win xmax]
  3477.     foreach v [sparseListWithParams $xfun x $parameters] {
  3478. #    puts v=$v
  3479. #    proc _xf {  x  } "return \[expr { $v } \]"
  3480.     proc _xf {  x  } "expr { $v }"    
  3481.     regsub "\\$" $v "" label
  3482.     lappend xfundata [list label $label] \
  3483.       [linsert [calculatePlot $win _xf $nsteps]  \
  3484.         0 xversusy]
  3485.     }
  3486.  
  3487.     # in case only functions and no y autoscale dont bother.
  3488.     if { "$data" != "" || [lsearch $autoscale y]>=0  } {
  3489.     set ranges [plot2dGetDataRange [concat $data $xfundata]]
  3490. #    puts ranges=$ranges
  3491.     foreach {v k} [eval plot2dRangesToRadius $ranges] {
  3492.         if { [lsearch $autoscale [string index $v 1] ] >= 0 } {
  3493.         oset $win [string range $v 1 end] $k
  3494.         }
  3495.     }
  3496.     }
  3497.     
  3498.     setUpTransforms $win 1.0
  3499.     set rtosx rtosx$win ; set rtosy rtosy$win
  3500.     $c del axes
  3501.     $c create line [$rtosx 0 ] [$rtosy -1000] [$rtosx 0] [$rtosy 1000] -fill $axisGray -tags axes
  3502.     $c create line [$rtosx -1000] [$rtosy 0] [$rtosx 1000] [$rtosy 0] -fill $axisGray -tags axes
  3503.     axisTicks $win $c
  3504.  
  3505.     if { "$xfun" != "" } {
  3506.      oset $win maintitle [concat list "Plot of y = \[oget $win xfun\]" ]
  3507.     }
  3508.     $c del path
  3509.     $c del label
  3510.     oset  $win curveNumber -1
  3511.     redraw2dData $win -tags path
  3512.     $c create text    [expr {[$rtosx 0] + 10}] [expr {[$rtosy [oget $win ymax]] +20}] -text [oget $win yaxislabel] -anchor nw
  3513.     $c create text     [expr {[$rtosx [oget $win xmax]] -20}] [expr {[$rtosy 0] - 10}] -text [oget $win xaxislabel] -anchor se
  3514.  
  3515.     
  3516. }
  3517.  
  3518.  
  3519.  
  3520. #
  3521.  #-----------------------------------------------------------------
  3522.  #  Should change name to plotData since works for 3d to now..
  3523.  # plot2dData --  create WIN and plot 2d OR 3d DATA which is a list of 
  3524.  #  data sets.  Each data set must begin with xversusy or againstIndex
  3525.  #  In the first case the data set looks like:
  3526.  #       { xversusy {x1 x2 ...xn} {y1 ... yn yn+1 ... ym} }
  3527.  #  and will be plotted as m/n curves : (x1,y1) (x2,y2) .. (xn,yn)
  3528.  #  and (x1,yn+1) (x2,yn+2) ..
  3529.  #  In the againstIndex case the x values are replace by the indices
  3530.  #  0,1,2,... [length $yvalues]-1 
  3531.  #  Results: none
  3532.  #
  3533.  #  Side Effects: curves draw
  3534.  #
  3535.  #----------------------------------------------------------------
  3536. #
  3537. proc plot2dData { win data args } {
  3538.    clearLocal $win
  3539.     #puts "data=$data, [regexp plot2d $data junk ]"
  3540.     if { [regexp plot2d $data junk] } {
  3541.   # eval plot2d $args -windowname $win  [plot2dGetRanges $data] -xfun [list {}] -data [list $data]
  3542.    eval plot2d $args -windowname $win   -xfun [list {}] -data [list $data]    
  3543.     } else {
  3544.     # puts data=$data
  3545.     set com [concat \
  3546.         plot3d $args -windowname $win -zfun {{}} -data [lrange $data 1 end]]
  3547.     # puts com=$com
  3548.     eval $com
  3549.     }
  3550.  }
  3551.  
  3552.  
  3553.  
  3554. proc plot2dGetDataRange { data } {
  3555.     set rangex ""
  3556.     set rangey ""
  3557.      #puts "data=$data"
  3558.     set extra ""
  3559.     foreach d $data {
  3560.     #puts first=[lindex $d 0]
  3561.       if { [catch {     
  3562.     switch -exact -- [lindex $d 0] {
  3563.        xversusy {
  3564.            foreach { xx yy } [lrange $d 1 end] {
  3565.           # puts "hi xx=[llength $xx],yy=[llength $yy]"
  3566.            if { [llength $xx] > 0 } {
  3567.                set rangex [minMax $xx $rangex]
  3568.                set rangey [minMax $yy $rangey]
  3569.            }
  3570.            }
  3571.            #puts "rangex=$rangex,rangey=$rangey"
  3572.        }
  3573.        againstIndex {
  3574.            set rangex [minMax [list 0 [llength [lindex $d 1]]] $rangex]
  3575.            set rangey [minMax [lindex $d 1] $rangey]
  3576.        }
  3577.        default {
  3578.            set vv [lindex $d 0]
  3579.            if { [lsearch {xrange yrange   } $vv] >= 0 } {
  3580.            set radius [expr {([lindex $d 2] -[lindex $d 1])/2.0 }]
  3581.            set center [expr {([lindex $d 2] +[lindex $d 1])/2.0 }]
  3582.            set var [string range $vv 0 0]
  3583.            lappend extra -${var}radius $radius -${var}center $center
  3584.            }
  3585.            if { [lsearch bargraph $vv] >= 0 } {
  3586.                set rangey [minMax 0 $rangey]
  3587.            }
  3588.  
  3589.  
  3590.            if { [lsearch {xradius yradius xcenter ycenter } $vv] >= 0 } {
  3591.            lappend extra -$vv [list [lindex $d 1]]
  3592.            }
  3593.  
  3594.         }
  3595.        }
  3596.    } errmsg ] } {
  3597.        set com [list error "bad data: [string range $d 0 200].." $errmsg]
  3598.        after 1 $com
  3599.    }
  3600.  }
  3601.  
  3602.    list $rangex $rangey $extra
  3603. }
  3604.  
  3605.  
  3606.  
  3607. proc plot2dRangesToRadius  { rangex rangey extra } {
  3608.    set ranges ""
  3609.   # puts "extra=$extra"
  3610.    foreach u { x y } {
  3611.        if { "[assoc -[set u]radius $extra]" == "" } {
  3612.        desetq "min max" [set range$u]
  3613.        if { "$min" == "$max" } {
  3614.            set min [expr {$min - .5}]
  3615.            set max [expr {$max + .5}]
  3616.        }
  3617.        #puts "$u has $min,$max"
  3618.        # use 1.7 to get a bit bigger radius than really necessary.
  3619.        if { "$max" != "" } {
  3620.        
  3621.            lappend extra -[set u]radius [expr {($max-$min)/1.7}] \
  3622.                -[set u]center [expr {($max+$min)/2.0}]
  3623.        }
  3624.    }
  3625.  }
  3626.  # puts "extra=$extra"
  3627.  return $extra
  3628. }
  3629.    
  3630.  
  3631. proc redraw2dData { win  args } {
  3632.    makeLocal $win c linecolors data xfundata errorbar linewidth
  3633.    set tags [assoc -tags $args {} ]
  3634.    set rtosx rtosx$win ; set rtosy rtosy$win  
  3635.    set i -1
  3636.    set label _default
  3637.    append data " " $xfundata
  3638. #    set linewidth 2.4
  3639.     
  3640.    #puts "data=$data"
  3641.    foreach d $data {
  3642.        set type [lindex $d 0]
  3643.        switch  $type {
  3644.        xversusy {
  3645.             #puts "starting .. [oget $win curveNumber]"
  3646.            set curvenumber [oget $win curveNumber]
  3647.            # the data can be multiple lists and each list
  3648.            # will not be line connected to previous
  3649.            foreach {xvalues yvalues} [lrange $d 1 end] {
  3650.            # puts "xvalues=$xvalues"
  3651.            #puts "here:$curvenumber,[oget $win curveNumber]"
  3652.            oset $win curveNumber $curvenumber
  3653.            set n [expr {[llength $xvalues] -1}]
  3654.            while { [llength $yvalues] > 0 } {
  3655.                set ans ""
  3656.                set color [nextColor $win]
  3657.                catch { set color [oget $win color] }
  3658.                
  3659.                if { [info exists didLabel([oget $win curveNumber])] } {
  3660.                set label "" } else { set didLabel([oget $win curveNumber]) 1
  3661.                }
  3662.                set errorbar [oget $win errorbar]
  3663.                # puts "errorbar=$errorbar"
  3664.                if { $errorbar != 0 } {
  3665.                set j 0
  3666.               # puts "xvalues=$xvalues,yvalues=$yvalues"
  3667.                     for { set i 0 } { $i <= $n } {incr i} {
  3668.                    set x [lindex $xvalues $i]
  3669.                    set y1 [lindex $yvalues [expr {$i * 2}]]
  3670.                    set y2 [lindex $yvalues [expr { $i * 2 +1}]]
  3671.                if { 1 } {
  3672.                   # puts "x=$x,y1=$y1,y2=$y2"
  3673.                    set xx [$rtosx $x]
  3674.                    set y1 [$rtosy $y1]
  3675.                    set y2 [$rtosy $y2]
  3676.                    $c create line [expr {$xx - $errorbar}] $y1 [expr {$xx +$errorbar}] $y1 $xx $y1 $xx $y2 [expr {$xx -$errorbar}] $y2 [expr {$xx + $errorbar}] $y2  -tags [list [concat $tags line[oget $win curveNumber]]]  -fill $color
  3677.                }
  3678.                }
  3679.                
  3680.                    
  3681.                set yvalues [lrange $yvalues [llength $xvalues] end]
  3682.                } else { 
  3683.  
  3684.                foreach x $xvalues y [lrange $yvalues 0 $n] {
  3685.                append ans "[$rtosx $x] [$rtosy $y] "
  3686.                
  3687.                }
  3688.  
  3689.                drawPlot $win [list $ans] -tags [list [concat $tags line[oget $win curveNumber]]]  -fill $color -label $label
  3690.                }
  3691.                set label _default
  3692.  
  3693.                set yvalues [lrange $yvalues [llength $xvalues] end]
  3694.            }
  3695.  
  3696.          } }
  3697.        againstIndex {
  3698.                set color [nextColor $win]
  3699.            set ind 0
  3700.            set ans ""
  3701.            foreach y [lindex $d 1] {
  3702.            append ans "[$rtosx $ind] [$rtosy $y] "
  3703.            incr ind
  3704.            }
  3705.            
  3706.            drawPlot $win [list $ans] -tags \
  3707.                [list [concat $tags line[oget $win curveNumber]]] \
  3708.                -fill $color -width $linewidth -label $label
  3709.            set label _default
  3710.  
  3711. #           eval $c create line $ans -tags \
  3712. #                [list [concat $tags line[oget $win curveNumber]]] \
  3713. #               -fill $color -width .2
  3714.        }
  3715.        label {
  3716.            set label [lindex $d 1]
  3717.        }
  3718.        default {
  3719.  
  3720.            # puts "$type,[lindex $d 1]"
  3721.            if { [lsearch { xfun color plotpoints linecolors pointsize nolines bargraph errorbar maintitle linewidth
  3722.            labelposition
  3723.            xaxislabel yaxislabel } $type] >= 0 } {
  3724.            # puts "setting oset $win $type [lindex $d 1]"
  3725.            oset $win $type [lindex $d 1]
  3726.            } elseif { "$type" == "text" } {
  3727.            desetq "x y text" [lrange $d 1 end]
  3728.            $c create text [$rtosx $x] [$rtosy $y] -anchor nw -text $text -tags "text all" -font times-roman
  3729.            }
  3730.  
  3731.        }
  3732.  
  3733.        }
  3734.    }
  3735.  
  3736. }
  3737.  
  3738. proc plot2dDrawLabel { win label color } {
  3739.     makeLocal $win c labelposition
  3740.     #puts "$win $label $color"
  3741.     if { "$label" == ""} {return }
  3742.     set bb [$c bbox label]
  3743.     desetq "a0 b0" $labelposition
  3744.     if { "$bb" == "" } { set bb "$a0 $b0 $a0 $b0" }
  3745.     desetq "x0 y0 x1 y1" $bb
  3746.     set leng  15
  3747.     set last [$c create text [expr {$a0 +$leng +4}] \
  3748.         [expr {2 + $y1}] \
  3749.         -anchor nw       -text "$label" -tags label]
  3750.     desetq "ux0 uy0 ux1 uy1" [$c bbox $last]
  3751.     $c create line $a0 [expr {($uy0+$uy1) /2}] [expr {$a0 +$leng}] [expr {($uy0+$uy1) /2}]   -tags "label" -fill $color
  3752. }
  3753.     
  3754.  
  3755. proc RealtoScreen { win listPts } {
  3756.     set rtosx rtosx$win ; set rtosy rtosy$win  
  3757.     set ans ""
  3758.     if { [llength [lindex $listPts  0]] != 1 } {
  3759.     foreach v $listPts {
  3760.         append ans " {"
  3761.         append ans [RealtoScreen $win $v]
  3762.         append ans "}"
  3763.     }
  3764.     }    else {
  3765.     foreach {x y } $listPts {
  3766.         append ans " [$rtosx $x] [$rtosy $y]"
  3767.     }
  3768.     }
  3769.     return $ans
  3770. }
  3771.  
  3772. proc drawPlot {win listpts args } {
  3773.     makeLocal $win  c nolines plotpoints  pointsize bargraph linewidth
  3774. #    set linewidth 2.4
  3775.     # puts ll:[llength $listpts]
  3776.     set tags [assoc -tags $args ""]
  3777.     if { [lsearch $tags path] < 0 } {lappend tags path}
  3778.     set fill [assoc -fill $args black]
  3779.     set label [assoc -label $args ""]
  3780.     if { "$label" == "_default" } {
  3781.     set label line[oget $win curveNumber]
  3782.     }
  3783.  
  3784.     catch { set fill [oget $win color] }
  3785.     
  3786.     if { $nolines == 1 && $plotpoints == 0 && $bargraph == 0} {
  3787.     set plotpoints 1
  3788.     }
  3789.  
  3790.     catch { 
  3791.     foreach pts $listpts {
  3792.     if { $bargraph } {
  3793.         set rtosy rtosy$win
  3794.         set rtosx rtosx$win
  3795.         set width [expr {abs([$rtosx $bargraph] - [$rtosx 0])}]
  3796.         set w2 [expr {$width/2.0}]
  3797.         # puts "width=$width,w2=$w2"
  3798.         set ry0 [$rtosy 0]
  3799.         foreach { x y } $pts {
  3800.         $c create rectangle [expr {$x-$w2}] $y  [expr {$x+$w2}] \
  3801.             $ry0 -tags $tags -fill $fill }
  3802.         } else {
  3803.         if { $plotpoints } {
  3804.             set im [getPoint $pointsize $fill]
  3805.             
  3806.             # there is no eval, so we need this.
  3807.             if { "$im" != "" } {
  3808.             foreach { x y } $pts {
  3809.             $c create image $x $y -image $im -anchor center \
  3810.                 -tags "$tags point"
  3811.             }
  3812.             } else {
  3813.             foreach { x y } $pts {
  3814.             $c create oval [expr {$x -$pointsize}] \
  3815.                 [expr {$y -$pointsize}] [expr {$x +$pointsize}] \
  3816.                 [expr {$y +$pointsize}] -tags $tags \
  3817.                 -fill $fill -outline {}
  3818.             
  3819.             }
  3820.         }
  3821.         }
  3822.         
  3823.         if { $nolines == 0 } {
  3824.             set n [llength $pts]
  3825.             set i 0
  3826.             set res "$win create line "
  3827.             #puts npts:[llength $pts]
  3828.             if { $n >= 6 } {
  3829.             eval $c create line $pts      -tags [list $tags] -width $linewidth -fill $fill
  3830.             }
  3831.         }
  3832.         }
  3833.         
  3834.     }
  3835.     }
  3836.     plot2dDrawLabel $win $label $fill
  3837. }
  3838.  
  3839.     
  3840.  
  3841. proc drawPointsForPrint { c } {
  3842.     global ws_openMath
  3843.     foreach v [$c find withtag point] {
  3844.     set tags [ldelete point [$c gettags $v]]
  3845.     desetq "x y" [$c coords $v]
  3846.     
  3847.     
  3848.     desetq "pointsize fill" $ws_openMath(pointimage,[$c itemcget $v -image])
  3849.     catch { 
  3850.         $c create oval [expr {$x -$pointsize}] \
  3851.             [expr {$y -$pointsize}] [expr {$x +$pointsize}] \
  3852.             [expr {$y +$pointsize}] -tags $tags \
  3853.                 -fill $fill -outline {}
  3854.          $c delete $v            
  3855.     }
  3856.  
  3857.  
  3858.     }
  3859.  
  3860. }
  3861.  
  3862. array set ws_openMath { bitmap,disc4 {#define disc4_width 4
  3863. #define disc4_height 4
  3864. static unsigned char disc4_bits[] = {
  3865.     0x06, 0x0f, 0x0f, 0x06};}
  3866.     bitmap,disc6 {#define disc_width 6
  3867. #define disc_height 6
  3868. static unsigned char disc_bits[] = {
  3869.     0xde, 0xff, 0xff, 0xff, 0xff, 0xde};}
  3870. }
  3871.  
  3872.  
  3873. proc getPoint { size color } {
  3874.     global ws_openMath
  3875.     set im ""
  3876.     if { ![catch { set im $ws_openMath(pointimage,$size,$color) }] } {
  3877.     return $im
  3878.     }
  3879.     catch { set data $ws_openMath(bitmap,disc[expr {$size * 2}]) 
  3880.     set im [image create bitmap -data $data -foreground $color]
  3881.     set ws_openMath(pointimage,$size,$color) $im
  3882.     set ws_openMath(pointimage,$im) "$size $color"
  3883.    }
  3884.     return $im
  3885. }
  3886.     
  3887.  
  3888.  
  3889.  
  3890. proc sliderCommandPlot2d { win var val } {
  3891.     linkLocal $win recompute
  3892.     updateParameters $win $var $val
  3893.     set com "recomputePlot2d $win"
  3894. # allow for fast move of slider...    
  3895.     after cancel $com
  3896.     after 10 $com
  3897. }
  3898.  
  3899. proc recomputePlot2d { win } {
  3900.        replot2d $win
  3901. }
  3902.  
  3903.  
  3904. ## endsource plot2d.tcl
  3905. ## source plot3d.tcl
  3906.  
  3907. ###### plot3d.tcl ######
  3908. ############################################################
  3909. # Netmath       Copyright (C) 1998 William F. Schelter     #
  3910. # For distribution under GNU public License.  See COPYING. # 
  3911. ############################################################
  3912.  
  3913.  
  3914. set ws_openMath(speed) [expr {(9700.0 / (1 + [lindex [time {set i 0 ; while { [incr i] < 1000} {}} 1] 0]))}]
  3915.  
  3916.  
  3917. set plot3dOptions { 
  3918.     {xradius 1 "Width in x direction of the x values" }
  3919.     {yradius 1 "Height in y direction of the y values"}
  3920.  
  3921.     {width 500 "Width of canvas in pixels"}
  3922.     {height 500 "Height of canvas in pixels" }
  3923.     {xcenter 0.0 {(xcenter,ycenter) is the origin of the window}}
  3924.     {ycenter 0.0 "see xcenter"}
  3925.     {zcenter 0.0 "see xcenter"}
  3926.     {bbox "" "xmin ymin xmax ymax zmin zmax overrides the -xcenter etc"}
  3927.     {zradius auto " Height in z direction of the z values"}
  3928.     {az 60 "azimuth angle" }
  3929.     {el 30 "elevantion angle" }
  3930.     
  3931.     {thetax 10.0 "ignored is obsolete: use az and el"}
  3932.     {thetay 20.0 "ignored is obsolete: use az and el"}
  3933.     {thetaz 30.0 "ignored is obsolete: use az and el"}
  3934.  
  3935.     {flatten 0 "Flatten surface when zradius exceeded" }
  3936.     {zfun "" "a function of z to plot eg: x^2-y^2"}
  3937.     {parameters "" "List of parameters and values eg k=3,l=7"}
  3938.     {sliders "" "List of parameters ranges k=3:5,u"}
  3939.     {data  "" "a data set of type { variable_grid xvec yvec zmatrix}
  3940.     or {matrix_mesh xmat ymat zmat} or {grid {xmin xmax} {ymin ymax} zmatrix}"}
  3941.     {nsteps "10 10" "steps in x and y direction"}
  3942.     {rotationcenter "" "Origin about which rotation will be done"}
  3943.     {zoomfactor "1.6 1.6" "Factor to zoom the x and y axis when zooming.  Zoom out will be reciprocal" }
  3944.     {screenwindow "20 20 700 700" "Part of canvas on screen"}
  3945.     {windowname ".plot3d" "window name"}
  3946. }
  3947.     
  3948.  
  3949. ## source matrix.tcl
  3950.  
  3951. ###### matrix.tcl ######
  3952. ############################################################
  3953. # Netmath       Copyright (C) 1998 William F. Schelter     #
  3954. # For distribution under GNU public License.  See COPYING. # 
  3955. ############################################################
  3956.  
  3957. # In this file a matrix is represented by a list of M*N entries together
  3958. # with an integer N giving the number of columns: {1 0 0 1} 2  would give
  3959. # the two by two identity
  3960.  
  3961. proc comment {args } { }
  3962.   set mee " } \] \[ expr { "  
  3963.  
  3964. proc mkMultLeftExpr { mat n prefix { constant "" } } {
  3965. #create a function body that does MAT (prefix1,prefix2,..) + constant 
  3966.     global mee
  3967.     set all ""
  3968.     
  3969.     set vars ""
  3970.     for { set i 0} { $i < $n} {incr i} { append vars " $prefix$i" }
  3971.     set j 0
  3972.     set k 0
  3973.     
  3974.     foreach v $mat {
  3975.     if { $j == 0 } {
  3976.         set ro ""
  3977.         # append ans ""
  3978.         set op ""
  3979.     }
  3980.         append ro " $op $v*\$$prefix$j"
  3981.     set op "+"
  3982.     if { $j == [expr {$n -1}] } {
  3983.          append ans " "
  3984.         if { "[lindex $constant $k]" != "" } {
  3985.         append ro " + [lindex $constant $k] "
  3986.         }
  3987.         incr k
  3988.         append ans [concat \[ expr [list $ro] \]]
  3989.         set j -1
  3990.     }
  3991.     incr j
  3992.     }
  3993.     # puts [list $vars $ans]
  3994.      return [list $vars $ans]
  3995. }
  3996.  
  3997. proc mkMultLeftFun { mat n name { constant ""} } {
  3998.     set expr [mkMultLeftExpr $mat $n _a $constant]
  3999.     set bod1 [string trim [lindex $expr 1] " "]
  4000. #    set bod "return \"$bod1\""
  4001.     set bod [concat list [lindex $expr 1]]
  4002.     proc $name [lindex $expr 0] $bod
  4003. }
  4004.  
  4005. proc rotationMatrix { th ph } {
  4006.    return [list \
  4007.        [expr {cos($ph)*cos($th)}] [expr {- cos($ph)*sin($th)}] [expr {sin($ph)}] \
  4008.        [expr {sin($th)}] [expr {cos($th)}] 0.0 \
  4009.        [expr {- sin($ph)*cos($th)}] [expr {sin($ph)*sin($th)}] [expr {cos($ph)}]]
  4010. }
  4011.  
  4012. # proc rotationMatrix { thx thy thz } {
  4013. #   return [list  \
  4014. #  [expr { cos($thy)*cos($thz)} ]  \
  4015. #  [expr { cos($thy)*sin($thz)} ]  \
  4016. #  [expr { sin($thy)} ]  \
  4017. #  [expr { sin($thx)*sin($thy)*cos($thz)-cos($thx)*sin($thz)} ]  \
  4018. #  [expr { sin($thx)*sin($thy)*sin($thz)+cos($thx)*cos($thz)} ]  \
  4019. #  [expr { -sin($thx)*cos($thy)} ]  \
  4020. #  [expr { -sin($thx)*sin($thz)-cos($thx)*sin($thy)*cos($thz)} ]  \
  4021. #  [expr { -cos($thx)*sin($thy)*sin($thz)+sin($thx)*cos($thz)} ]  \
  4022. #  [expr { cos($thx)*cos($thy)} ] ]
  4023. # }
  4024.  
  4025. proc rotationMatrix { thx thy thz } {
  4026.     return \
  4027.  [list  \
  4028.  [expr { cos($thy)*cos($thz) } ] \
  4029.  [expr { cos($thy)*sin($thz) } ] \
  4030.  [expr { sin($thy) } ] \
  4031.  [expr { sin($thx)*sin($thy)*cos($thz)-cos($thx)*sin($thz) } ] \
  4032.  [expr { sin($thx)*sin($thy)*sin($thz)+cos($thx)*cos($thz) } ] \
  4033.  [expr { -sin($thx)*cos($thy) } ] \
  4034.  [expr { -sin($thx)*sin($thz)-cos($thx)*sin($thy)*cos($thz) } ] \
  4035.  [expr { sin($thx)*cos($thz)-cos($thx)*sin($thy)*sin($thz) } ] \
  4036.  [expr { cos($thx)*cos($thy) } ] ]
  4037. }
  4038.  
  4039. # cross [a,b,c] [d,e,f] == [B*F-C*E,C*D-A*F,A*E-B*D]
  4040. # cross_product([a,b,c],[d,e,f]):=[B*F-C*E,C*D-A*F,A*E-B*D]
  4041. # cross_product(u,v):=sublis([a=u[1],b=u[2],c=u[3],d=v[1],e=v[2],f=v[3]],[B*F-C*E,C*D-A*F,A*E-B*D]);
  4042. # the rotation by azimuth th, and elevation ph
  4043. # MATRIX([COS(TH),SIN(TH),0],[-COS(PH)*SIN(TH),COS(PH)*COS(TH),SIN(PH)],
  4044. #        [SIN(PH)*SIN(TH),-SIN(PH)*COS(TH),COS(PH)]);
  4045.  
  4046. proc rotationMatrix { th ph {ignore {} } } {
  4047.     return \
  4048. [list \
  4049. [        expr {cos($th)   } ]\
  4050. [expr {sin($th)   } ]\
  4051. 0 \
  4052. [expr {-cos($ph)*sin($th)   } ]\
  4053. [expr {cos($ph)*cos($th)   } ]\
  4054. [expr {sin($ph)   } ]\
  4055. [expr {sin($ph)*sin($th)   } ]\
  4056. [expr {-sin($ph)*cos($th)   } ]\
  4057. [expr {cos($ph)   } ]]
  4058. }
  4059.  
  4060. proc setMatFromList {name lis n} {
  4061.     set i 1
  4062.     set j 1
  4063.     foreach v $lis {
  4064.     uplevel 1 set [set name]($i,$j) $v
  4065.     if { $j == $n } {set j 1; incr i} else { incr j}
  4066. }   }
  4067.  
  4068. proc matRef { mat cols i j } { [lindex $mat [expr {$i*$cols + $j}]] }
  4069. proc matTranspose { mat cols } {
  4070.     set j 0
  4071.     set m [expr {[llength $mat ] / $cols}]
  4072.     while { $j < $cols} {
  4073.     set i 0
  4074.     while { $i < $m } {
  4075.         append ans " [lindex $mat [expr {$i*$cols + $j}]]"
  4076.         incr i
  4077.     }
  4078.     incr j
  4079.     }
  4080.     return $ans
  4081. }
  4082.  
  4083.  
  4084. proc matMul { mat1 cols1 mat2 cols2 } {
  4085.     mkMultLeftFun $mat1 $cols1 __tem
  4086.     set tr [matTranspose $mat2 $cols2]
  4087.     set rows1 [expr {[llength $mat1] / $cols1}]
  4088.     #puts "tr=$tr"
  4089.     set upto [llength $tr]
  4090.     set j 0
  4091.     set ans ""
  4092.     set i 0
  4093.     while { $j < $cols2  } {
  4094.     append ans " [eval __tem [lrange $tr $i [expr {$i+$cols1 -1}]]]"
  4095.     incr i $cols1
  4096.     incr j
  4097.     }
  4098.  #   return $ans
  4099.    # puts "matTranspose $ans $rows1"
  4100.     return [matTranspose $ans $rows1]
  4101. }
  4102.  
  4103.  
  4104.  
  4105. proc invMat3 { mat } {
  4106.     setMatFromList xx $mat 3
  4107.     set det [expr { double($xx(1,1))*($xx(2,2)*$xx(3,3)-$xx(2,3)*$xx(3,2))-$xx(1,2)* \
  4108.         ($xx(2,1)*$xx(3,3)-$xx(2,3)*$xx(3,1))+$xx(1,3)*($xx(2,1)*$xx(3,2)\
  4109.         -$xx(2,2)*$xx(3,1)) }]
  4110.     
  4111.     return [list   [expr { ($xx(2,2)*$xx(3,3)-$xx(2,3)*$xx(3,2))/$det}] \
  4112.         [expr { ($xx(1,3)*$xx(3,2)-$xx(1,2)*$xx(3,3))/$det}] \
  4113.         [expr { ($xx(1,2)*$xx(2,3)-$xx(1,3)*$xx(2,2))/$det}] \
  4114.         \
  4115.         [expr { ($xx(2,3)*$xx(3,1)-$xx(2,1)*$xx(3,3))/$det}] \
  4116.         [expr { ($xx(1,1)*$xx(3,3)-$xx(1,3)*$xx(3,1))/$det}] \
  4117.         [expr { ($xx(1,3)*$xx(2,1)-$xx(1,1)*$xx(2,3))/$det}] \
  4118.         \
  4119.         [expr { ($xx(2,1)*$xx(3,2)-$xx(2,2)*$xx(3,1))/$det}] \
  4120.         [expr { ($xx(1,2)*$xx(3,1)-$xx(1,1)*$xx(3,2))/$det}] \
  4121.         [expr { ($xx(1,1)*$xx(2,2)-$xx(1,2)*$xx(2,1))/$det}]]
  4122. }
  4123.  
  4124.  
  4125. proc vectorOp { a op b} {
  4126.     set i [llength $a]
  4127.     set k 0
  4128.     set ans [expr [list [lindex $a 0]  $op [lindex $b 0]]]
  4129.     while { [incr k] < $i } {
  4130.     lappend ans  [expr  [list [lindex $a $k] $op [lindex $b $k]]]
  4131.     }
  4132.     return $ans
  4133. }
  4134. ## endsource matrix.tcl
  4135.  
  4136. proc transformPoints { pts fun } {
  4137.   set ans ""
  4138.   foreach { x y z } $pts {
  4139.       append ans " "
  4140.       append ans [$fun $x $y $z]
  4141.   }
  4142.   return $ans
  4143. }
  4144.  
  4145. proc calculatePlot3d {win fun  nx ny } {
  4146.     global plot3dMeshes$win
  4147.     set meshes  plot3dMeshes$win
  4148.     makeLocal $win xradius xmin yradius ymin zradius zcenter flatten
  4149.     
  4150.     set stepx [expr { 2*$xradius / double($nx)}]
  4151.     set stepy [expr { 2*$yradius / double($ny)} ]
  4152.     set i 0
  4153.     set j 0
  4154.     set zmax -1000000000
  4155.     set zmin 1000000000
  4156.     # check if zradius is a number
  4157.     set dotruncate [expr ![catch {expr {$zradius + 1} }]]
  4158.     if { $dotruncate } {
  4159.     if { $flatten } { set dotruncate 0 }
  4160.     set zzmax [expr {$zcenter + $zradius}]
  4161.     set zzmin [expr {$zcenter - $zradius}]
  4162.     #puts "zzmax=$zzmax,$zzmin"
  4163.    } else { set flatten 0 }
  4164.  
  4165.     catch { unset  $meshes }
  4166.     set k 0
  4167.     for {set i 0} { $i <= $nx } { incr i} {
  4168.     set x [expr { $xmin + $i * $stepx }]
  4169.     for {set j 0} { $j <= $ny } { incr j} {
  4170.         set y [expr { $ymin + $j *$stepy }]
  4171.        if { [catch {  set z [$fun $x $y] }] } {
  4172.            set z nam
  4173.        } elseif { $dotruncate  &&  ($z > $zzmax || $z < $zzmin) } {
  4174.            set z nam
  4175.  
  4176.         } else {
  4177.         if { $flatten } {
  4178.             if { $z > $zzmax } { set z $zzmax } elseif {
  4179.             $z < $zzmin } { set z $zzmin }}
  4180.             
  4181.            if { $z < $zmin }  { set zmin $z } elseif {
  4182.         $z > $zmax } { set zmax $z }
  4183.         if { $j != $ny && $i != $nx } {
  4184.             set [set meshes]($k) \
  4185.                       "$k [expr { $k+3 }] [expr { $k+3+($ny+1)*3 }] \
  4186.               [expr { $k+($ny+1)*3 }]"} else {
  4187.           # set plot3dMeshes($k) ""
  4188.           }
  4189.       }
  4190.           incr k 3
  4191.         append ans " $x $y $z"
  4192.     }
  4193.     }
  4194.     oset $win zmin $zmin
  4195.     oset $win zmax $zmax
  4196.     oset $win points $ans
  4197.     oset $win nx $nx
  4198.     oset $win ny $ny
  4199.     oset $win colorfun plot3dcolorFun
  4200.     addAxes $win
  4201.     setupPlot3dColors $win
  4202. }
  4203.  
  4204. proc calculatePlot3data {win fun  nx ny } {
  4205. # calculate the 3d data from function:
  4206.     makeLocal $win xradius xmin xmax ymax yradius ymin zradius zcenter flatten
  4207.     
  4208.     set rowx [linspace $xmin $xmax $nx]
  4209.     set rowy [linspace $ymin $ymax $ny]
  4210.     foreach  y $rowy {
  4211.     set row ""
  4212.     foreach x $rowx {
  4213.         if { [catch {  set z [$fun $x $y] }] } {
  4214.         set z nam
  4215.         }
  4216.         lappend row $z
  4217.     }
  4218.     lappend matrix $row
  4219.     }
  4220.     global silly
  4221.     set silly [list variable_grid $rowx $rowy $matrix ]
  4222.     return [list variable_grid $rowx $rowy $matrix ]
  4223.     
  4224. }
  4225.  
  4226. proc addAxes { win } {
  4227.     #global plot3dPoints plot3dMeshes xradius yradius xcenter ycenter
  4228.     global [oarray $win] plot3dMeshes$win
  4229.     linkLocal $win lmesh
  4230.     makeLocal $win   xradius yradius xcenter ycenter  points zmax zcenter zmin
  4231.     set meshes plot3dMeshes$win
  4232.     set ll [llength $points]
  4233.  
  4234.     # puts "oset $win  axisstart  $ll"
  4235.     oset $win  axisstart  $ll
  4236.     set nx2 5
  4237.     set ny2 5
  4238.     set xstep [expr { 1.2 * $xradius/double($nx2) }]
  4239.     set ystep [expr { 1.2 * $yradius/double($ny2) }]
  4240.     set nz2 $ny2
  4241.  
  4242.     set ans " "
  4243.     set x0 $xcenter
  4244.     set y0 $ycenter
  4245.     set z0 $zcenter
  4246.  
  4247.     set k $ll
  4248.     for { set i 0 } { $i < $nx2 } { incr i } {
  4249.     append ans "[expr {$x0 +$i * $xstep}] $y0 $z0 "
  4250.     lappend lmesh [list $k [incr k 3]]
  4251.     #set [set meshes]($k) "$k [incr k 3]"
  4252.     }
  4253.     append ans "[expr {$x0 +$nx2 * $xstep}] $y0 $z0 "
  4254.     incr k 3
  4255.     # set plot3dMeshes($k) ""
  4256.  
  4257.     for { set i 0 } { $i < $ny2 } { incr i } {
  4258.     append ans "$x0 [expr {$y0 +$i * $ystep}] $z0 "
  4259.     lappend lmesh [list $k [incr k 3]]
  4260.     #set [set meshes]($k) "$k [incr k 3]"
  4261.     }
  4262.     append ans "$x0 [expr {$y0 +$ny2 * $ystep}] $z0 "
  4263.     incr k 3
  4264.     # set $meshes($k) ""
  4265.  
  4266.     set zstep [expr {1.2 * $zmax/double($nz2)}]
  4267.     if { $zstep < $ystep } { set zstep $ystep }
  4268.     
  4269.     for { set i 0 } { $i < $ny2 } { incr i } {
  4270.     append ans "$x0 $y0 [expr {$z0 +$i * $zstep}] "
  4271.     # puts "set [set meshes]($k) \"$k [incr k 3]\""
  4272.     lappend lmesh [list $k [incr k 3]]
  4273.     # set [set meshes]($k) "$k [incr k 3]"
  4274.     }
  4275.     append ans "$x0 $y0 [expr {$z0 +$nz2 * $zstep}] "
  4276.     incr k 3
  4277.     # puts "ans=$ans"
  4278.     append [oloc $win points] $ans
  4279.     
  4280.    # set $meshes($k) ""
  4281.  
  4282. }
  4283.  
  4284. proc addBbox { win } {
  4285.     global plot3dMeshes$win
  4286.     makeLocal $win xmin xmax ymin ymax zmin zmax  cmap
  4287.     linkLocal $win points lmesh 
  4288.     set ll [llength $points]
  4289.      append points " $xmin $ymin $zmin \
  4290.         $xmax $ymin $zmin \
  4291.             $xmin $ymax $zmin \
  4292.             $xmax $ymax $zmin \
  4293.             $xmin $ymin $zmax \
  4294.         $xmax $ymin $zmax \
  4295.             $xmin $ymax $zmax \
  4296.             $xmax $ymax $zmax "
  4297.     foreach  { a b } { 0 1 0 2 2 3 3 1
  4298.                        4 5 4 6 6 7 7 5
  4299.     0 4 1 5 2 6 3 7  }  {
  4300.     set k [expr {$a*3 + $ll}]
  4301.     set l [expr {$b*3 + $ll}]
  4302.     # set plot3dMeshes${win}($k) [list $k $l]
  4303.     lappend lmesh [list $k $l]
  4304.     }
  4305.     lappend lmesh [list $ll]
  4306.     oset $win $cmap,[list $ll [expr {$ll + 3}]] red
  4307.     oset $win $cmap,[list $ll [expr {$ll + 6}]] blue
  4308.     oset $win $cmap,[list $ll [expr {$ll + 12}]] green
  4309.     
  4310.     oset $win special($ll) "drawOval [oget $win c] 3 -fill red -tags axis"
  4311. }
  4312.  
  4313. proc drawOval { c radius args } {
  4314.     set ll [llength $args]
  4315.     set x [lindex $args [expr {$ll -2}]]
  4316.     set y [lindex $args [expr {$ll -1}]]
  4317.     set rest [lrange $args 0 [expr {$ll -3}]]
  4318.     set com [concat $c create oval [expr {$x - $radius}]  [expr {$y - $radius}] [expr {$x + $radius}]  [expr {$y + $radius}] $rest]
  4319.     eval $com
  4320. }
  4321.     
  4322.  
  4323. proc plot3dcolorFun {win z } {
  4324.     makeLocal $win zmin zmax
  4325.     set ncolors 180
  4326.     set tem [expr {(180/$ncolors)*round(($z - $zmin)*$ncolors/($zmax - $zmin+.001))}]
  4327.     #puts "tem=$tem,z=[format %3g $z],[format "#%.2x%.2x%.2x" 50 50 $tem]"
  4328.     return [format "#%.2x%.2x%.2x" [expr {180 -$tem}] [expr {240 - $tem}] $tem]
  4329. }
  4330.  
  4331. proc setupPlot3dColors { win } {
  4332.     upvar #0 [oarray $win] wvar
  4333.     # the default prefix for cmap
  4334.     set wvar(cmap) c1
  4335.     set k 0
  4336.     makeLocal $win colorfun points
  4337.     foreach { x y z } $points {
  4338.     catch { set wvar(c1,$k) [$colorfun $win $z] }
  4339.     incr k 3 
  4340.     }
  4341. }
  4342.  
  4343. proc calculateRotated { win } {
  4344.     set pideg [expr {3.14159/180.0}]
  4345.     linkLocal $win scale
  4346.     makeLocal $win az el rotationcenter xradius zradius yradius
  4347.     set rotmatrix [rotationMatrix [expr {$az * $pideg }] \
  4348.         [expr {$el * $pideg }] \
  4349.       ]
  4350.  
  4351.     # shrink by .2 on z axis
  4352.     # set fac [expr  {[vectorlength $xradius $yradius] / (sqrt(2) * $zradius)}]
  4353.  
  4354.     set rotmatrix [ matMul  $rotmatrix 3 $scale 3 ]
  4355.     set tem [matMul $scale 3 $rotationcenter 1]
  4356.     
  4357.     mkMultLeftFun  $rotmatrix 3 _rot$win
  4358.     set rot _rot$win
  4359.     set ans ""
  4360.     # puts "points=[oget $win points]"
  4361.     if { "$rotationcenter" != "" } {
  4362.     #puts "rotationcenter = $rotationcenter"
  4363.     set constant [vectorOp $tem - [eval $rot $rotationcenter]]
  4364.     mkMultLeftFun  $rotmatrix 3 _rot$win $constant
  4365.     }
  4366.     #puts "win $win"
  4367.     foreach { x y z } [oget $win points] {
  4368.     if { [catch { append ans " " [$rot $x $y $z] } ] } {
  4369.         append ans "  nam nam nam " }
  4370.     }
  4371.     oset $win rotatefun $rot
  4372.     oset $win rotated $ans 
  4373. }
  4374.  
  4375. proc getOrderedMeshIndices { win } {
  4376.  #   global  plot3dMeshes$win
  4377.  #    set meshes plot3dMeshes$win
  4378.     linkLocal $win lmesh
  4379.     # puts "array names $meshes =[array names $meshes ]"
  4380.     # get the list offset by 2, so the lindex indices grab the Z coordinate.
  4381.     # without having to add 2.
  4382.     set pts2 [lrange [oget $win rotated] 2 end]
  4383.     set i 0
  4384.     foreach tem $lmesh {
  4385.         set k [llength $tem]
  4386.        if { [catch {
  4387.         if {  $k == 4 } {
  4388.         set z [expr { ([lindex $pts2 [lindex $tem 0]] \
  4389.             +[lindex $pts2 [lindex $tem 1]] \
  4390.             + [lindex $pts2 [lindex $tem 2]] \
  4391.             + [lindex $pts2 [lindex $tem 3]])/4.0 }]
  4392.     } elseif { $k == 2 } {
  4393.             set z [expr { ([lindex $pts2 [lindex $tem 0]] \
  4394.             +[lindex $pts2 [lindex $tem 1]])/2.0 }]
  4395.     } else {
  4396.         set z 0
  4397.             foreach w $tem {
  4398.         set z [expr {$z + [lindex $pts2 $w] }  ]
  4399.         
  4400.         }    
  4401.         set z [expr { $z/double($k)}]
  4402.         }
  4403.     lappend ans [list $z $i]
  4404.     # append pp($z) "$i "
  4405.     incr i
  4406.     
  4407.          } ]} {
  4408.         set lmesh [lreplace $lmesh $i $i]
  4409.      }
  4410.     }
  4411.     set ttem [lsort -real -index 0 $ans]
  4412.     set ans {}
  4413.     foreach v $ttem {
  4414.     lappend ans [lindex $v 1]
  4415.     }
  4416.     oset $win meshes $ans
  4417.     return
  4418. }
  4419.  
  4420.  
  4421. proc setUpTransforms3d { win } {
  4422.     global screenwindow
  4423.     #set scr $screenwindow
  4424.     # setUpTransforms $win .7
  4425.     # set screenwindow $scr
  4426.     linkLocal $win scale
  4427.         makeLocal $win xcenter ycenter xradius yradius c zmin zmax xmin xmax ymin ymax zradius
  4428.     #dshow xcenter ycenter xradius yradius c zmin zmax xmin xmax ymin ymax zradius
  4429.     set fac .5
  4430.  
  4431.     set delx [$c cget -width]
  4432.     set dely [$c cget -height]
  4433.     set f1 [expr {(1 - $fac)/2.0}]
  4434.  
  4435.     set scale [list [expr {1.5/($xradius)}] 0 0 0 [expr {1.5/($yradius)}] 0 0 0 [expr {1.5/($zradius)}] ]
  4436.  
  4437.     set x1 [expr {$f1 *$delx}]
  4438.     set y1 [expr {$f1 *$dely}]
  4439.     set x2 [expr {$x1 + $fac*$delx}]
  4440.     set y2 [expr {$y1 + $fac*$dely}]
  4441.     # set xmin [expr {($xcenter - $xradius) * 1.5/ ($xradius)}]
  4442.     # set ymin [expr {($ycenter - $yradius) * 1.5/ ($yradius)}]
  4443.     # set xmax [expr {($xcenter + $xradius) * 1.5/ ($xradius)}]
  4444.     # set ymax [expr {($ycenter + $yradius) * 1.5/ ($yradius)}]
  4445.     #puts "RANGES=$xmin,$xmax $ymin,$ymax $zmin,$zmax"
  4446.     desetq "xmin ymin" [matMul $scale 3 "$xmin $ymin 0" 1]
  4447.     desetq "xmax ymax" [matMul $scale 3 "$xmax $ymax 0" 1]
  4448.     #puts "RANGES=$xmin,$xmax $ymin,$ymax $zmin,$zmax"
  4449.     # set transform [makeTransform "$xmin $ymin $x1 $y2" "$xmin $ymax $x1 $y1 " "$xmax $ymin $x2 $y2"]
  4450.    # desetq "xmin xmax ymin ymax" "-2 2 -2 2"
  4451.  
  4452.     set transform [makeTransform "$xmin $ymin $x1 $y2" "$xmin $ymax $x1 $y1 " "$xmax $ymin $x2 $y2"]
  4453.     oset $win transform $transform
  4454.     oset $win transform0 $transform
  4455.     
  4456.     getXtransYtrans $transform rtosx$win rtosy$win
  4457.     getXtransYtrans [inverseTransform $transform] storx$win story$win 
  4458.  
  4459. }
  4460.  
  4461.  
  4462. proc plot3d { args } {
  4463.     global  plot3dOptions
  4464.     set win [assoc -windowname $args]
  4465.     if { "$win" == "" } {
  4466.     set win [getOptionDefault windowname $plot3dOptions] }
  4467.     clearLocal $win
  4468.     apply mkPlot3d  $win $args
  4469. #    bind $win <Configure> {}    
  4470.     replot3d $win
  4471. }
  4472.  
  4473. proc replot3d { win } {
  4474.     global   printOption plot2dOptions
  4475.     makeLocal $win nsteps zfun data c
  4476.     linkLocal $win parameters sliders
  4477.     
  4478.     oset $win maintitle    "concat \"Plot of z = [oget $win zfun]\""
  4479.     if { [llength $nsteps] == 1 }    {
  4480.     oset $win nsteps \
  4481.         [set nsteps  [list [lindex $nsteps 0] [lindex $nsteps 0]]]
  4482.     }
  4483.     foreach v $data {
  4484.     if { "[assq [lindex $v 0] $plot2dOptions notthere]" != "notthere" } {
  4485.         oset $win [lindex $v 0] [lindex $v 1]
  4486.     }
  4487.     }
  4488.     if { "$sliders" != "" && ![winfo exists $c.sliders] } {
  4489.     addSliders $win
  4490.     }
  4491.  
  4492.     if { "$zfun" != "" } {
  4493.     proc _xf {  x  y } "return \[expr { [sparseWithParams $zfun {x y} $parameters ] } \]"
  4494.     addOnePlot3d $win [calculatePlot3data $win _xf  [lindex $nsteps 0] [lindex $nsteps 1]]
  4495.     # calculatePlot3d $win _xf [lindex $nsteps 0] [lindex $nsteps 1]
  4496.     }
  4497.  
  4498.     if { "$data" != "" } {
  4499.     if { 0 } {
  4500.         puts "here"
  4501.     set ranges [ plot3dGetDataRange [list $data]]
  4502.     linkLocal $win zmin zmax
  4503.     desetq "zmin zmax" [lindex $ranges 2]
  4504.     puts "ranges=$ranges"
  4505.     set some [plot2dRangesToRadius [lindex $ranges 0] [lindex $ranges 1] ""]
  4506.     puts "and now"
  4507.     foreach {v k} $some {
  4508.         puts "oset $win [string range $v 1 end] $k"
  4509.         oset $win [string range $v 1 end] $k
  4510.     }
  4511.         }
  4512.     
  4513.     addOnePlot3d $win $data
  4514.     }
  4515.  
  4516.  
  4517.     setUpTransforms3d $win
  4518.  
  4519.     oset $win colorfun plot3dcolorFun
  4520. #    addAxes $win
  4521.     oset $win cmap c1
  4522.     setupPlot3dColors $win
  4523.     addBbox $win
  4524.     # grab the bbox just as itself
  4525.     global ws_openMath
  4526.     linkLocal $win lmesh
  4527.     if { [llength $lmesh] >   100 * $ws_openMath(speed)  } {
  4528.     # if we judge that rotation would be too slow, we make a secondary list
  4529.     # of meshes (random) including the bbox, and display those. 
  4530.     linkLocal $win  points lmeshBbox pointsBbox
  4531.     set n [llength $lmesh]
  4532.     set lmeshBbox [lrange $lmesh [expr {$n -13}] end]
  4533.     set i 0 ;
  4534.     while { [incr i ] < ( 35*$ws_openMath(speed)) } {
  4535.         set j [expr {round(floor(rand()*($n-13))) }]
  4536.         if { ![info exists temm($j)] } {
  4537.         lappend lmeshBbox [lindex $lmesh $j ]
  4538.         set temm(j) 1
  4539.         }
  4540.     }
  4541.     resetPtsForLmesh $win
  4542.     }
  4543.     oset $win lastAnglesPlotted ""
  4544.     setView $win ignore
  4545.  
  4546. proc setView { win ignore } {
  4547.     global timer
  4548.     foreach v [after info] {
  4549.      #puts "$v=<[after info $v]>"
  4550.     if { "[lindex [after info $v] 0]" == "setView1" } {
  4551.         after cancel $v
  4552.     }
  4553.     }
  4554.     after 2 setView1 $win
  4555. }
  4556.  
  4557. proc setView1 { win  } {
  4558.     linkLocal $win lastAnglesPlotted points
  4559.     set new [list [oget  $win az] [oget  $win el] ]
  4560.     if { "$new" != "$lastAnglesPlotted" } {
  4561.        makeLocal $win c
  4562.     calculateRotated $win
  4563.     getOrderedMeshIndices $win
  4564.     drawMeshes $win $c
  4565.     oset $win lastAnglesPlotted $new
  4566.     }
  4567. }
  4568.  
  4569. proc setQuick { win on } {
  4570.   linkLocal $win  lmesh  points savedData cmap     lmeshBbox pointsBbox
  4571.     if { $on } {
  4572.     if { ![info exists savedData] && [info exists lmeshBbox] } {
  4573.         set savedData [list $lmesh $points $cmap]
  4574.         set lmesh $lmeshBbox
  4575.         set points $pointsBbox
  4576.         set cmap c2
  4577.     }
  4578.     } else {
  4579.     if { [info exists savedData] } {
  4580.         desetq "lmesh points cmap" $savedData
  4581.         unset savedData
  4582.         oset $win lastAnglesPlotted ""
  4583. }   }   }
  4584.  
  4585.  
  4586. # reduce the set of pointsBbox to include only those needed by lmeshBbox
  4587. proc resetPtsForLmesh { win } {
  4588.     upvar 1 lmeshBbox lmeshBbox
  4589.     upvar 1 pointsBbox pointsBbox
  4590.     upvar 1 points points
  4591.     upvar #0 [oarray $win] wvar
  4592.     set k 0
  4593.     foreach v $lmeshBbox {
  4594.     if { [llength $v] == 1 } {
  4595.         lappend nmesh $v
  4596.     } else {
  4597.         set s ""
  4598.         foreach w $v {
  4599.         if { [info exists tem($w)] } {
  4600.             lappend s $tem($w)
  4601.         } else {
  4602.             set tem($w) $k
  4603.             lappend s $k
  4604.             lappend pointsBbox \
  4605.                 [lindex $points $w] \
  4606.                 [lindex $points [expr {$w +1}]] \
  4607.                 [lindex $points [expr {$w +2}]]
  4608.             catch {set wvar(c2,$k) $wvar(c1,$w)}
  4609.             incr k 3
  4610.         
  4611.         }
  4612.             
  4613.         }
  4614.         lappend nmesh $s
  4615.         if { [info exists wvar(c1,$v)] } {
  4616.         set wvar(c2,$s) $wvar(c1,$v)
  4617.         }
  4618.     }
  4619.     }
  4620.     set lmeshBbox  $nmesh
  4621. }
  4622.  
  4623. proc drawMeshes {win canv} {
  4624.     # $canv delete poly
  4625.     # only delete afterwards, to avoid relinquishing the colors
  4626.     $canv addtag oldpoly withtag poly 
  4627.     $canv delete axis
  4628.     makeLocal $win lmesh rotated cmap
  4629.     upvar #0 [oarray $win] ar
  4630.     proc _xf { x} [info body rtosx$win]
  4631.     proc _yf { y} [info body rtosy$win]
  4632.     foreach { x y z} $rotated { lappend rotatedxy [_xf $x] [_yf $y] 0 }
  4633.  
  4634.     foreach k [oget $win meshes] {
  4635.     #puts "drawOneMesh $win $canv $k"
  4636.     #puts "drawOneMesh $win $canv $k"
  4637.     set mesh [lindex $lmesh $k]
  4638.     set col gray70
  4639.     catch { set col $ar($cmap,[lindex $mesh 0]) }
  4640.     drawOneMesh $win $canv $k $mesh $col
  4641.     }
  4642.     $canv delete oldpoly
  4643. }
  4644.  
  4645.  
  4646. #
  4647.  #-----------------------------------------------------------------
  4648.  # plot3dMeshes  --  given K an index in plot3dPoints(points) 
  4649.  # if this is the index of a lower grid corner, return the other points.
  4650.  # k takes values 0,3,6,9,... the values returned all have a 3 factor,  
  4651.  # and so are true lindex indices into the list of points.
  4652.  # returns {} if this is not a mesh point.
  4653.  #  Results:
  4654.  #
  4655.  #  Side Effects: none... NOTE we should maybe cash this in an array. 
  4656.  #
  4657.  #----------------------------------------------------------------
  4658. #
  4659.  
  4660. proc drawOneMesh { win  canv k mesh color } {
  4661.     #k=i*(ny+1)+j
  4662.     # k,k+1,k+1+nyp,k+nyp
  4663.     upvar 1 rotatedxy ptsxy
  4664.     set n [llength $mesh]
  4665.  
  4666.     foreach kk $mesh {
  4667.     lappend coords [lindex $ptsxy $kk] [lindex $ptsxy [expr {$kk + 1}]]
  4668.     }
  4669.     if { $n <= 2 } {
  4670.     #puts "drawing $k,n=$n $coords, points $mesh "
  4671.     #desetq "a b" $mesh
  4672.     #puts "<[lrange $points $a [expr {$a +2}]]> <[lrange $points $b [expr {$b +2}]]"
  4673.     if { $n == 2 } {
  4674. #        set color gray70
  4675. #        catch { set color [oget $win $cmap,$mesh]}
  4676.             
  4677.         eval $canv create line $coords -tags [list [list axis mesh.$k]] \
  4678.             -fill $color -width 5 
  4679.     } else {
  4680.        # puts "doing special $mesh, $coords"
  4681.         catch { set tem [oget $win special([lindex $mesh 0])]
  4682.         eval [concat $tem $coords]
  4683.     }
  4684.     }
  4685.     } else {
  4686.      eval $canv create polygon $coords -tags [list [list poly mesh.$k]] \
  4687.         -fill $color \
  4688.         -outline black
  4689.     }
  4690. }
  4691.  
  4692. proc doHelp3d { win } {
  4693.  global Parser
  4694.  doHelp $win [join [list \
  4695.  
  4696. William Schelter's plotter for three dimensional graphics.
  4697.  
  4698. To QUIT this HELP click here.
  4699.  
  4700. By clicking on Zoom, the mouse now allows you \
  4701. to zoom in on a region of the plot.  Each click \
  4702. near a point magnifies the plot, keeping the \
  4703. center at the point you clicked.  Depressing \
  4704. the SHIFT key while clicking zooms in the \
  4705. opposite direction.
  4706.  
  4707. Clicking on Rotate, makes the left mouse button  \
  4708. cause rotation of the image.   The current position \
  4709. can be determined by azimuth and elevation angles \
  4710. which are given under the Config menu.   They may also \
  4711. be specified on the command line.
  4712.  
  4713. To change the equations enter in the entry \
  4714. windows, and click on replot.
  4715.  
  4716. You may print to a postscript printer, or save the plot \
  4717. as a postscript file, by clicking on save.   To change \
  4718. between printing and saving see the Print Options under Config.
  4719.     
  4720. Clicking with the right mouse button and dragging may be used \
  4721. instead of the scroll bars to slide the plot \
  4722. around.
  4723.  
  4724.  
  4725. } $Parser(help)]]
  4726. }
  4727.  
  4728. proc     makeFrame3d { win } {
  4729.   global plot3dPoints
  4730.    set w [makeFrame $win 3d]
  4731.     set top $w
  4732.     catch { set top [winfo parent $w]}
  4733.     catch {
  4734.  
  4735.     wm title $top "Schelter's 3d Plot Window"
  4736.     wm iconname $top "DF plot"
  4737.  #   wm geometry $top 750x700-0+20
  4738.    }
  4739.   
  4740.     pack $w
  4741.  
  4742. }
  4743.     
  4744. proc mkPlot3d { win  args } {
  4745.     global plot3dOptions  printOption [oarray $win] axisGray
  4746.  
  4747.     getOptions $plot3dOptions $args -usearray [oarray $win]
  4748.     #puts "$win width=[oget $win width],args=$args"
  4749.     setPrintOptions $args
  4750.     set printOption(maintitle) ""
  4751.     set wb $win.buttons
  4752.     setupCanvas $win
  4753.    # catch { destroy $win }
  4754.     makeFrame3d $win
  4755.     oset $win sliderCommand sliderCommandPlot3d
  4756.    oset $win noaxisticks 1
  4757.    
  4758.    makeLocal $win buttonFont c
  4759.     bind $c <Motion> "showPosition3d $win %x %y"
  4760.     button $wb.rotate -text "Rotate" -command "setForRotate $win" -font $buttonFont
  4761.    setBalloonhelp $win $wb.rotate {Dragging the mouse with the left button depressed will cause the object to rotate.  The rotation keeps the z axis displayed in an upright position (ie parallel to the sides of the screen), but changes the viewpoint.   Moving right and left changes the azimuth (rotation about the z axis), and up and down changes the elevation (inclination of z axis).   The red,blue and green sides of the bounding box are parallel to the X, Y and Z axes, and are on the smaller side.} 
  4762.  
  4763.    $win.position config -width 15
  4764.     pack $wb.rotate -expand 1 -fill x
  4765.    setForRotate $win
  4766.  
  4767.     
  4768. }   
  4769.  
  4770. proc doConfig3d { win } {
  4771.  
  4772.     
  4773.     desetq "wb1 wb2" [doConfig $win]
  4774.  
  4775.     makeLocal $win buttonFont
  4776.  
  4777.     mkentry $wb1.zfun [oloc $win zfun]  "z=f(x,y)" $buttonFont 
  4778.     mkentry $wb1.nsteps [oloc $win nsteps]  "Number of mesh grids"  $buttonFont 
  4779.     # button .jim.buttons.rot "rotate" -command "bindForRotation"
  4780.     # pack .jim.buttons.rot
  4781.     pack $wb1.zfun  $wb1.nsteps
  4782.     pack        $wb1.zfun  $wb1.nsteps 
  4783.    foreach w {xradius yradius xcenter ycenter zcenter zradius parameters } {
  4784.     mkentry $wb1.$w [oloc $win $w] $w $buttonFont
  4785.     pack $wb1.$w 
  4786.     }
  4787.  
  4788.     scale $wb1.rotxscale -label "azimuth"  \
  4789.         -orient horizontal -length 150 -from -180 -to 180 -resolution 1 \
  4790.         -command "setView $win" -variable [oloc $win az] -tickinterval 120 -font $buttonFont 
  4791.  
  4792.     scale $wb1.rotyscale -label "elevation"  \
  4793.         -orient horizontal -length 150 -from -180 -to 180 -resolution 1 \
  4794.         -command "setView $win" -variable [oloc $win el] -tickinterval 120 -font $buttonFont 
  4795.  
  4796.  
  4797. #    scale $wb1.rotzscale -label "thetaz"  \
  4798. #        -orient horizontal -length 150 -from -180 -to 180 \
  4799. #        -command "setView $win" -variable [oloc $win thetaz] -tickinterval 120 -font $buttonFont 
  4800.  
  4801.     pack   $wb1.rotxscale   $wb1.rotyscale   
  4802.  
  4803. }
  4804.  
  4805.  
  4806. proc showPosition3d { win x y } {
  4807.    # global position c
  4808.     makeLocal $win c
  4809.     set x [$c canvasx $x]
  4810.     set y [$c canvasy $y]
  4811.     set it [ $c find closest $x $y]
  4812.     set tags [$c gettags $it]
  4813.     if { [regexp {mesh[.]([0-9]+)} $tags junk k] } {
  4814.     set i 0
  4815.     set min 1000000
  4816.     set at 0
  4817.     # find closest.
  4818.     foreach {x1 y1} [$c coords $it] {
  4819.         set d [expr {($x1 - $x)*($x1 - $x)+($y1 - $y)*($y1 - $y)}]
  4820.         if { $d < $min} { set at $i ; set min $d }
  4821.         incr i
  4822.     }
  4823.     set mesh [lindex [oget $win lmesh] $k]
  4824.     set ll [lindex $mesh $at]
  4825.     set pt [lrange [oget $win points] $ll [expr {$ll + 2}]]
  4826.     # puts pt=$pt
  4827.     catch { oset $win position [eval [concat "format {(%.2f %.2f %.2f)}" $pt]] }
  4828.     }
  4829. #    oset $win position [format {(%.1f %.1f)} $x $y]
  4830. #    oset $win position \
  4831. #      "[format {(%.2f,%.2f)}  [storx$win [$c canvasx $x]] [story$win [$c canvasy $y]]]"
  4832. }
  4833.  
  4834.  
  4835.  
  4836. #
  4837.  #-----------------------------------------------------------------
  4838.  #
  4839.  # rotateRelative --  do a rotation indicated by a movement
  4840.  # of dx,dy on the screen.  
  4841.  #
  4842.  #  Results:
  4843.  #
  4844.  #  Side Effects: 
  4845.  #
  4846.  #----------------------------------------------------------------
  4847. #
  4848.  
  4849. proc rotateRelative { win x1 x2 y1 y2 } {
  4850.     makeLocal $win c az el rotatefun
  4851.     set x1 [$c canvasx $x1]
  4852.     set x2 [$c canvasx $x2]
  4853.     set y1 [$c canvasy $y1]
  4854.     set y2 [$c canvasy $y2]
  4855.     set xx [expr {$x2-$x1}]
  4856.     set yy [expr {($y2-$y1)}]
  4857.     set res [$rotatefun 0 0 1]
  4858.     set res1 [$rotatefun 0 0 0]
  4859.     set fac [expr {([lindex $res 1] > [lindex $res1 1] ? -1 : 1) }] ;
  4860.    # puts "fac=$fac,[lindex $res 1],[lindex $res1 1]"
  4861.     oset $win az [reduceMode360 [expr   {round($az + $fac *  $xx /2.0) }]]
  4862.     oset $win el [reduceMode360 [expr   {round($el -  $yy /2.0) }]]
  4863.     setView $win ignore
  4864.  
  4865.  
  4866. }
  4867.  
  4868. proc reduceMode360 { n } {
  4869.   return [  expr fmod(($n+180+5*360),360)-180]
  4870.  
  4871. }
  4872.  
  4873. proc setForRotate { win} {
  4874.     makeLocal $win c
  4875.     $c delete printrectangle
  4876.     bind $c  <Button-1> "setQuick $win 1 ; doRotateScreen $win %x %y "
  4877.     bind $c  <ButtonRelease-1> "setQuick $win 0 ; setView $win ignore"
  4878. }
  4879. proc doRotateScreen { win x y } {
  4880.     makeLocal $win c
  4881.     oset $win lastx $x
  4882.     oset $win lasty $y
  4883.     bind $c <B1-Motion> "doRotateScreenMotion $win %x %y"
  4884.     
  4885.  
  4886. }
  4887.  
  4888. proc doRotateScreenMotion {win x y } {
  4889.     makeLocal $win lastx lasty
  4890.     set dx [expr {$x - $lastx}]
  4891.     set dy [expr {$y - $lasty}]
  4892.     if { [vectorlength $dx $dy] < 4 } { return }
  4893.     rotateRelative $win $lastx $x $lasty $y
  4894.     oset $win lastx $x
  4895.     oset $win lasty $y
  4896.     
  4897. }
  4898.  
  4899.     
  4900. proc sliderCommandPlot3d { win var val } {
  4901.     linkLocal $win recompute
  4902.     updateParameters $win $var $val
  4903.     set com "recomputePlot3d $win"
  4904. # allow for fast move of slider...    
  4905.     after cancel $com
  4906.     after 10 $com
  4907. }
  4908.  
  4909. proc recomputePlot3d { win } {
  4910.     linkLocal $win  recompute
  4911.     if { [info exists recompute]  } {
  4912.     incr recompute
  4913.     return
  4914.     } else {
  4915.         set recompute 1
  4916.     }
  4917.     set redo 0
  4918.     while { $redo != $recompute } {
  4919.     set redo $recompute
  4920. #    puts "replot3d $win,[oget $win parameters]"
  4921.     catch {replot3d $win }
  4922.     update
  4923.     }
  4924.     unset recompute
  4925. }
  4926.  
  4927.  
  4928. ## endsource plot3d.tcl
  4929. ## source nplot3d.tcl
  4930.  
  4931. ###### nplot3d.tcl ######
  4932. ############################################################
  4933. # Netmath       Copyright (C) 1998 William F. Schelter     #
  4934. # For distribution under GNU public License.  See COPYING. # 
  4935. ############################################################
  4936.  
  4937. # source plotting.tcl ; source nplot3d.tcl ; catch { destroy .plot3d} ;  plot3d -zfun "" -data $sample -xradius 10 -yradius 10
  4938. # newidea:
  4939. # { plot3d
  4940. #  { gridequal {minx maxx} {miny maxy}
  4941. #   {{z00 z01 z02 .. z0n } { z10 z11 z12 .. z1n} {..  } ...}
  4942. #  { grid {x0 x1  xm} {y0 y1 yn } miny maxy}
  4943. #   {{z00 z01 z02 .. z0n } { z10 z11 z12 .. z1n} {..  } ...}
  4944. #  { xyzgrid {{x00 y00 z00 x01 y01 z01 .. x0  }{x0 x1  xm} {y0 y1 yn } miny maxy}
  4945. #   {{z00 z01 z02 .. z0n } { z10 z11 z12 .. z1n} {..  } ...}
  4946. # tclMesh(2*[0,0,0,0,0;1,1,1,1,1]-1,2*[0,1,1,0,0;0,1,1,0,0]-1,2*[0,0,1,1,0;0,0,1,1,0]-1)
  4947.   
  4948. #     { gridequal { 
  4949.  
  4950. # z00 z01 .. all belong to x=minx and y = miny,.... up y=maxy in n+1 steps
  4951. #{ grid {minx maxx} {miny maxy}
  4952. #  {{z00 z01 z02 .. z0n } { z10 z11 z12 .. z1n} {..  } ...}
  4953. # }
  4954. # where a mesh(1) {z00 z01 z11 z10} above 
  4955.  
  4956.  
  4957.  
  4958. # { mesh {{{x00 y00 z00 } { x01 y01 z01} { x02 y02 z02}  ..}{{x10 y10 z10} {x11 y11 z11} ......} ..}}
  4959. # mesh(1) = P00 P01 P11 P10
  4960.  
  4961. set sample { variable_grid { 0 1 2 } { 3 4 5} { {21 111 2} {3 4 5 } {6 7 8 }}}
  4962. set sample { variable_grid { 0 1 2 } { 3 4 5} { {0 1 2} {3 4 5 } {6 7 8 }}}
  4963. set sample { matrix_mesh {{0 1} { 2 3 } {4 5 }}  {{0 1} { 2 3 } {4 5 }}  {{0 1} { 2 3 } {4 5 }} }
  4964. set sample { matrix_mesh {{0 1 2} {0 1 2 } {0 1 2 }} {{3 4 5} {3 4 5} {3 4 5}} { {0 1 2} {3 4 5 } {6 7 8 }}}
  4965. set sample1 { variable_grid  { 1 2 3 4 5 6 7 8 9 10 }
  4966.  { 1 2 3 }
  4967.  {  { 0 0 0 0 0 0 0 0 0 0 }
  4968.  { 0 0.68404 1.28558 1.73205 1.96962 1.96962 1.73205 1.28558 0.68404 2.44921e-16 }
  4969.  { 0 1.36808 2.57115 3.4641 3.93923 3.93923 3.4641 2.57115 1.36808 4.89843e-16 }
  4970.  }  }
  4971.  
  4972. set sample { matrix_mesh  {  { 0 0 0 0 0 }
  4973.  { 1 1 1 1 1 }
  4974.  }  {  { 0 1 1 0 0 }
  4975.  { 0 1 1 0 0 }
  4976.  }  {  { 0 0 1 1 0 }
  4977.  { 0 0 1 1 0 }
  4978.  }  } 
  4979.  
  4980.     
  4981. proc  fixupZ { } {
  4982.     uplevel 1 {
  4983.     if { [catch { expr $z + 0 } ] } {
  4984.         set z nam
  4985.     }  elseif { $dotruncate  &&  ($z > $zzmax || $z < $zzmin) } {
  4986.         set z nam
  4987.         
  4988.     } else {
  4989.         if { $flatten } {
  4990.         if { $z > $zzmax } { set z $zzmax } elseif {
  4991.             $z < $zzmin } { set z $zzmin }}
  4992.             
  4993.             if { $z < $zmin }  { set zmin $z } elseif {
  4994.             $z > $zmax } { set zmax $z }
  4995.             }
  4996.         }
  4997. }
  4998.  
  4999.  
  5000. proc vectorLength { v } {
  5001.     expr { sqrt(1.0 * [lindex $v 0]*[lindex $v 0] + [lindex $v 1]*[lindex $v 1] + [lindex $v 2]*[lindex $v 2]) }
  5002. }
  5003.  
  5004. proc normalizeToLengthOne { v } {
  5005.     set norm [expr { sqrt(1.0 * [lindex $v 0]*[lindex $v 0] + [lindex $v 1]*[lindex $v 1] + [lindex $v 2]*[lindex $v 2]) }]
  5006.     if { $norm != 0.0 } {
  5007.     return [list [expr { [lindex $v 0] / $norm  } ] \
  5008.         [expr { [lindex $v 1] / $norm  } ] \
  5009.         [expr { [lindex $v 2] / $norm  } ] ]
  5010.      
  5011.     } else { return "1.0 0.0 0.0 " }
  5012. }
  5013.     
  5014.     
  5015.  
  5016. proc vectorCross { x1 x2 }  {
  5017.      list \
  5018.       [expr { [lindex $x1 1]*[lindex $x2 2]- [lindex $x2 1]*[lindex $x1 2]}] \
  5019.       [expr { [lindex $x1 2]*[lindex $x2 0]- [lindex $x2 2]*[lindex $x1 0] } ] \
  5020.       [expr { [lindex $x1 0]*[lindex $x2 1]- [lindex $x2 0]*[lindex $x1 1] }]
  5021. }
  5022.     
  5023. proc linspace { a b n } {
  5024.     if { $n < 2 } { error "from $a to $b requires at least 2 points" }
  5025.     set del [expr {($b - $a)*1.0/($n -1)  }]
  5026.     for { set i 0 } { $i < $n } { incr i } {
  5027.     lappend ans [expr {$a + $del * $i}]
  5028.     }
  5029.     return $ans
  5030. }
  5031.  
  5032.  
  5033. proc addOnePlot3d { win data } {
  5034.     upvar #0 plot3dMeshes$win meshes 
  5035.     #puts " adding meshes = plot3dMeshes$win"
  5036.     #puts "data=$data"
  5037.     linkLocal $win points zmax zmin zcenter zradius rotationcenter xradius yradius xmin xmax ymin ymax lmesh
  5038.     makeLocal $win flatten 
  5039.     catch { unset  meshes }
  5040.     set points ""
  5041.  
  5042.  
  5043.     set dotruncate [expr ![catch {expr {$zradius + 1} }]]
  5044.     set k [llength $points]
  5045.     set type [lindex $data 0]
  5046.     # in general the data should be a list of plots..
  5047.     if { [lsearch {grid mesh variable_grid matrix_mesh }  $type ]>=0 } {
  5048.     set alldata [list $data]
  5049.     } else {set alldata $data}
  5050.     foreach data $alldata {    
  5051.     set type [lindex $data 0]
  5052.     if { "$type" == "grid" } {
  5053.     desetq "xmin xmax" [lindex $data 1]
  5054.     desetq "ymin ymax" [lindex $data 2]
  5055.     set pts [lindex $data 3]
  5056.     
  5057.     set ncols [llength $pts]
  5058.     set nrows  [llength [lindex $pts 0]]
  5059.     set data [list variable_grid [linspace $xmin $xmax $ncols] \
  5060.         [linspace $ymin $ymax $nrows] \
  5061.         $pts ]
  5062.     }
  5063.     if { "$type" == "variable_grid" } {
  5064.     desetq "xrow yrow zmat" [lrange $data 1 end]
  5065.     # puts "xrow=$xrow,yrow=$yrow,zmat=$zmat"
  5066.     set nx [expr {[llength $xrow] -1}]
  5067.     set ny [expr {[llength $yrow] -1}]
  5068.     #puts "nx=$nx,ny=$ny"
  5069. #    set xmin [lindex $xrow 0]
  5070. #    set xmax [lindex $xrow $nx]
  5071. #    set ymin [lindex $yrow 0]
  5072. #    set ymax [lindex $yrow $ny]
  5073.     desetq "xmin xmax" [minMax $xrow ""]
  5074.     desetq "ymin ymax" [minMax $yrow ""]
  5075.     desetq "zmin zmax" [matrixMinMax [list $zmat]]
  5076. #    puts "and now"
  5077. #    dshow nx xmin xmax ymin ymax zmin zmax
  5078.     if { $dotruncate } {
  5079.         if { $flatten } { set dotruncate 0 }
  5080.  
  5081.         set zzmax [expr {$zcenter + $zradius}]
  5082.         set zzmin [expr {$zcenter - $zradius}]
  5083.         #puts "zzmax=$zzmax,$zzmin"
  5084.     } else { set flatten 0 }
  5085.  
  5086.  
  5087.  
  5088.     for {set j 0} { $j <= $ny } { incr j} {
  5089.         set y [lindex $yrow $j]
  5090.         set row [lindex $zmat $j]    
  5091.     for {set i 0} { $i <= $nx } { incr i} {
  5092.         set x [lindex $xrow $i]
  5093.         set z [lindex $row $i]
  5094.         #puts "x=$x,y=$y,z=$z, at ($i,$j)"
  5095.         fixupZ 
  5096.         if { $j != $ny && $i != $nx } {
  5097.         lappend lmesh [list $k [expr { $k+3 }] \
  5098.             [expr { $k+3+($nx+1)*3 }] \
  5099.               [expr { $k+($nx+1)*3 }]]
  5100.         }
  5101.           incr k 3
  5102.       lappend points $x $y $z
  5103.       }
  5104.     }
  5105.     } elseif { "$type" == "matrix_mesh" } {
  5106.     
  5107.     desetq "xmat ymat zmat" [lrange $data 1 end]
  5108.     foreach v {x y z} {
  5109.         
  5110.         
  5111.         desetq "${v}min ${v}max" [matrixMinMax [list [set ${v}mat]]]
  5112.         
  5113.     }
  5114.     #puts "zrange=$zmin,$zmax"
  5115.     set nj [expr {[llength [lindex $xmat 0]] -1 }]
  5116.     set ni [expr {[llength $xmat ] -1 }]
  5117.     set i -1
  5118.     set k [llength $points]
  5119.     foreach rowx $xmat rowy $ymat rowz $zmat {
  5120.         set j -1
  5121.         incr i
  5122.         if { [llength $rowx] != [llength $rowy] } {
  5123.         error "mismatch rowx:$rowx,rowy:$rowy"
  5124.         }
  5125.         if { [llength $rowx] != [llength $rowz] } {
  5126.         error "mismatch rowx:$rowx,rowz:$rowz"
  5127.         }
  5128.         foreach x $rowx y $rowy z $rowz {
  5129.         incr j
  5130.         if { $j != $nj && $i != $ni } {
  5131.         #puts "tes=($i,$j) $x, $y, $z"
  5132.             lappend lmesh [ list \
  5133.                 $k [expr { $k+3 } ] [expr { $k + 3  + ($nj+1)*3}] \
  5134.                 [expr { $k+($nj+1)*3 }] ]
  5135.         }
  5136.         incr k 3
  5137.         lappend points $x $y $z
  5138.         }
  5139.     }
  5140.     } elseif { 0 && "$type" == "mesh" } {
  5141.   # walk thru compute the xmin, xmax, ymin , ymax...
  5142.   # and then go thru setting up the mesh array..
  5143.   # and maybe setting up the color map for these meshes..
  5144.   #
  5145.     # { mesh {{{x00 y00 z00 } { x01 y01 z01} { x02 y02 z02}  ..}{{x10 y10 z10} {x11 y11 z11} ......} ..}}
  5146. # mesh(1) = P00 P01 P11 P10
  5147.     set mdata [lindex $data 1]
  5148.     set nx [llength $mdata]
  5149.     set ny [llength [lindex $mdata 0]]
  5150.     
  5151.     for {set i 0} { $i <= $nx } { incr i} {
  5152.     set pts [lindex $mdata $i]
  5153.     set j 0
  5154.     foreach { x y z} $pts {
  5155.         fixupZ $z
  5156.         if { $j != $ny && $i != $nx } {
  5157.         lappend lmesh [list 
  5158.             $k [expr { $k+3 }] [expr { $k+3+($ny+1)*3 }] \
  5159.             [expr { $k+($ny+1)*3 }] ]
  5160.         }
  5161.         }
  5162.         incr k 3
  5163.         lappend points $x $y $z
  5164.         incr j
  5165.     }
  5166.     }
  5167.    }
  5168.     foreach v { x y z } {
  5169.     set a [set ${v}min]
  5170.     set b  [set ${v}max]
  5171.     if { $a == $b } {
  5172.         set ${v}min [expr {$a -1}]
  5173.         set ${v}max [expr {$a +1}]
  5174.     }
  5175.     set ${v}radius [expr {($b - $a)/2.0}]
  5176.     set ${v}center [expr {($b + $a)/2.0}]
  5177.     }
  5178.     if { "$rotationcenter" == "" } {
  5179.     set rotationcenter "[expr {.5*($xmax + $xmin)}] [expr {.5*($ymax + $ymin)}]   [expr {.5*($zmax + $zmin)}] "
  5180.     }
  5181.     
  5182.     #puts "meshes data=[array get meshes]"
  5183.     #global plot3dMeshes.plot3d
  5184.     #puts "array names plot3dMeshes.plot3d = [array names plot3dMeshes.plot3d]"
  5185. }
  5186.  
  5187. proc vectorDiff { x1 x2 } {
  5188.     list [expr { [lindex $x1 0] - [lindex $x2 0] }] \
  5189.         [expr { [lindex $x1 1] - [lindex $x2 1] }] \
  5190.         [expr { [lindex $x1 2] - [lindex $x2 2] }]
  5191. }
  5192.  
  5193.  
  5194. proc oneCircle { old2 old1 pt radius nsides { angle 0 } } {
  5195.     set dt  [expr {  3.14159265358979323*2.0/($nsides-1.0) + $angle }]
  5196.     for  { set i 0 } { $i < $nsides } { incr i } {
  5197.     set t [expr {$dt*$i }]
  5198.     lappend ans [expr { $radius*([lindex $old2 0]*cos($t) + [lindex $old1 0] * sin($t)) + [lindex $pt 0] } ] \
  5199.         [expr { $radius*([lindex $old2 1]*cos($t) + [lindex $old1 1] * sin($t)) + [lindex $pt 1] } ] \
  5200.         [expr { $radius*([lindex $old2 2]*cos($t) + [lindex $old1 2] * sin($t)) + [lindex $pt 2] } ]
  5201.     }
  5202.     return $ans
  5203. }
  5204.  
  5205. proc curve3d { xfun yfun zfun trange } {
  5206.     foreach u { x y z} {
  5207.     set res [parseConvert [set ${u}fun] -variables t]
  5208.     proc _${u}fun { t } [list expr [lindex [lindex $res 0] 0]]
  5209. }   }
  5210.  
  5211. proc tubeFromCurveData { pts nsides radius } {
  5212.     set n [llength $pts] ;
  5213.     set closed [ expr { [vectorLength [vectorDiff [lindex $pts 0] [lindex $pts end]]] < .02} ]
  5214.     if { $closed } {
  5215.     set f1 [expr {$n -2}]
  5216.     set f2 1
  5217.     } else { set f1 0
  5218.      set f2 1
  5219.     }
  5220.     set delta [vectorDiff [lindex $pts $f2] [lindex $pts $f1]]
  5221.     if { [lindex $delta 0] == 0 && [lindex $delta 1] == 0 && [lindex $delta 2] == 0 } { set delta "0 0 1.0" }
  5222.     set old ".6543654 0.0765456443 0.2965433"
  5223.     set old1 [normalizeToLengthOne [vectorCross $delta $old]]
  5224.     set n1 $old1
  5225.     set n2 [normalizeToLengthOne [vectorCross $delta $old1]]
  5226.     set first1 $n1 ; set first2 $n2
  5227.     
  5228.     lappend ans [oneCircle $n2   old1 [lindex $pts 0]]
  5229.     for { set j 1 } { $j < $n -1 } { incr j } {
  5230.     set delta [vectorDiff [lindex $pts $j] [lindex $pts [expr {$j+1}]]]
  5231.     if { [lindex $delta 0] == 0 && [lindex $delta 1] == 0 && [lindex $delta 2] == 0 } { set delta $old
  5232.     }
  5233.     set old $delta
  5234.     set old1 [normalizeToLengthOne [vectorCross $delta $n1]]
  5235.     set old2 [normalizeToLengthOne [vectorCross $delta $n2]]
  5236.     set n2 $old1
  5237.     set n1 $old2
  5238.     lappend ans [oneCircle $n2 $n1 [lindex $pts $j] $radius $nsides]
  5239. }
  5240.     if { $closed } {
  5241.     set f2 1 ; set f1 [expr {$n -2}] ; set f3 0
  5242.     } else {
  5243.     set f1 [expr {$n -2}] ; set f2 [expr {$n-1}] ; set f3 $f2
  5244.     }
  5245.  
  5246.     set delta [vectorDiff [lindex $pts $f2] [lindex $pts $f1]]
  5247.     if { [lindex $delta 0] == 0 && [lindex $delta 1] == 0 && \
  5248.         [lindex $delta 2] == 0 } { set delta $old }
  5249.     set old1 [normalizeToLengthOne [vectorCross delta $n1]]
  5250.     set old2 [normalizeToLengthOne [vectorCross $n2 $delta]]
  5251.     set n2 $old1 ; set n1 $old2
  5252.     if { $closed } {
  5253.     set angle [vangle $first1 $n1]
  5254.     set n1 $first1 ; st n2 $first2;
  5255.     }
  5256.     lappend ans [oneCircle $n2 $n1 [lindex $pts $f3] $radius $nsides $angle]
  5257.    return $ans
  5258. }
  5259.  
  5260.  
  5261. #
  5262.  #-----------------------------------------------------------------
  5263.  #
  5264.  # vangle --  angle between two unit vectors
  5265.  #
  5266.  #  Results: an angle
  5267.  #
  5268.  #  Side Effects: none.
  5269.  #
  5270.  #----------------------------------------------------------------
  5271. #
  5272. proc vangle { x1 x2 } {
  5273.     set dot [expr { [lindex $x1 0]*[lindex $x2 0] +\
  5274.          [lindex $x1 1]*[lindex $x2 1] +\
  5275.          [lindex $x1 2]*[lindex $x2 2]} ]
  5276.     if { $dot >= 1 } { return 0.0 }
  5277.     if { $dot <= -1.0 } { return 3.141592653589 }
  5278.     return [expr { acos($dot) } ]
  5279. }
  5280.  
  5281. ## endsource nplot3d.tcl
  5282.  
  5283. # from shell 
  5284. # wish8.0 plotting.tcl -eval {plot2d -xfun  x^2+3}
  5285. # or in html
  5286. # <embed src=plotting.tcl eval="plot2d -xfun  x^2+3" >
  5287. #
  5288.  
  5289.  
  5290.  
  5291. omPlotAny [exec cat [lindex $argv 0]]
  5292.